# TD2 : Fichiers et exceptions ## Partie 1 : **Informations importantes sur les fichiers :** - Pour lire ou écrire un fichier, on doit d'abord l'ouvrir en spécifiant le chemin : ```python fichier = open("text.txt") # dans le dossier du script fichier = open("C:/Bureau/text.txt") # chemin complet ``` - Pour choisir le mode d'ouverture, plusieurs codes sont disponibles : - `r` en lecture - `w` en écriture (**supprime le contenu présent**) - `a` en écriture **après** le contenu déjà présent - `b` en mode binaire sans interprétation des données du fichier (pour des fichiers non-texte) ```python f_lecture = open("text.txt", "r") f_ajout = open("text.txt", "a") f_ecriture_binaire = open("binaire.bin", "wb") ``` - Pour lire et écrire dans le fichier, les méthodes `write()`, `readline()` et `readlines()` sont disponibles : ```python fichier = open("text.txt", "ra") # lecture + écriture # (1) Lire tout le fichier d'un coup contenu = fichier.readlines() # (2) Lire ligne par ligne for i in range(20): # 20 premières lignes ligne = fichier.readline() # Écriture fichier.write("bip boup\n") fichier. close() ``` ### GPS 1 Données : ``` 152902.00 4823.409837 00425.903959 66.804 152903.00 4823.409837 00425.903959 66.804 152904.00 4823.409837 00425.903959 66.804 152905.00 4823.409837 00425.903959 66.804 152906.00 4823.409837 00425.903959 66.804 152907.00 4823.409837 00425.903959 66.804 ... ``` Programme : - *Ouvrir* `GPS_data.txt` - *Lire* les 50 premières lignes - *Convertir* les données en flottants - *Stocker* le contenu dans une liste - *Afficher* la première ligne, première colonne - *Écrire* les données dans un autre fichier (`' '` entre chaque nombre, `'\n'` en fin de ligne) **Solution :** ```python def gps_1(): # Ouverture du fichier en lecture in_file = open('GPS_data.txt', 'r') # Création et remplissage de la liste des données data = [] for i in range(50): line = in_file.readline() # Lecture # Séparation de la chaine sur chaque espace data_txt = line.split(' ') # Conversion en float data_float = [float(x) for x in data_txt] data.append(data_float) # Ajout # Fermeture du fichier in_file.close() # Premiere ligne print(data[0]) # Premiere colonne print([line[0] for line in data]) # print(np.array(data)[:, 0]) # Écriture du fichier de sortie out_file = open('GPS_data_extract.txt', 'w') for line in data: line_txt = ' '.join([str(elt) for elt in line]) + '\n' out_file.write(line_txt) out_file.close() ``` ### GPS 2 Les exceptions permettent de gérer des erreurs et d'adapter le comportement du programme en fonction de celles-ci : ```python try: ... # Code erroné ou pouvant lever des exceptions ... except TypeError: print("Mauvais type") except NameError: print("Mauvais nom") except Exception: # Exception est le type par défaut print("Autre erreur") ``` Programme : - Même chose sur la totalité du fichier - Gérer les erreurs avec des **exceptions** **Solution :** ```python def gps_2(): # Ouverture du fichier en lecture in_file = open('GPS_data.txt', 'r') # Création et remplissage de la liste des données data = [] for line in in_file: # Séparation de la chaine sur chaque espace data_txt = line.split(' ') # Conversion en float try: data_float = [float(x) for x in data_txt] data.append(data_float) # Ajout except Exception: print("Données non conformes: ", line) # Fermeture du fichier in_file.close() ... ``` ### GPS 3 Le fichier GPS stocke les quatre éléments suivants : **temps**, **latitude**, **longitude** et **altitude**. Les latitudes et longitudes ont un format particulier qu'il faut convertir : ``` 48|23|.|409837 degré|minutes|.|décimales de minute en 48|.|39016395 degré|.|décimales de degré ``` Pour vous aider : - `//` est une division entière - `%` est le reste de la division entière - Une minute de degré est 1/60e de degré **Solution :** ```python def minutes_vers_degres(degres_minutes): # Extraction des deux premiers chiffres degres = degres_minutes // 100 # Extraction des deux derniers chiffres minutes = degres_minutes % 100 return degres + minutes/60.0 ``` Pour vous aider pour la suite : - Pour convertir `lat` et `long` en UTM, utilisez la fonction `LLUC.LLtoUTM(23, lat, -long)`. Cette fonction renvoie la zone, le "Easting" et le "Northing". - La fonction `np.mean()` permet de calculer la moyenne. - Enfin, vous pouvez afficher vos données avec `matplotlib` : ```python import mpl_toolkits.mplot3d.axes3d as p3 # Conversion en array numpy coords = np.array(coords) fig = plt.figure() ax = p3.Axes3D(fig) # plot3D a besoin de tableau 1 dimension ax.plot3D(coords[:, 1], coords[:, 2], coords[:, 3]) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') fig.add_axes(ax) plt.show() ``` **Solution :** ```python ... with open('GPS_data.txt', 'r') as in_file: coords = [] for line in in_file: data_txt = line.split() try: data_float = [float(x) for x in data_txt] lat = minutes_vers_degres(data_float[1]) longi = minutes_vers_degres(data_float[2]) (zone, e, n) = LLUC.LLtoUTM(23, lat, -longi) coords.append([data_float[0], e, n, data_float[3]]) except Exception: print("Données non conformes : ", line) ... ``` ### GPS 4 `re` est une bibliothèque d'expression régulière qui permettent de créer des modèles intelligents de validation de données. On veut s'en servir pour définir une ligne correcte : ``` nombre.nombre nombre.nombre nombre.nombre nombre.nombre temps latitude longitude altitude ``` Utilisez le site [regex101](https://regex101.com/) pour tester votre expression régulière. **Solution :** ``` (\d+\.\d+\ ){3}(\d+\.\d+$) ``` Une expression régulière s'utilise comme suit : ```python expr_reg = re.compile('he[a-zA-Z]+') # mot qui a pour suffixe 'he' expr_reg.match('hello') # True expr_reg.match('bipboup') # False expr_reg.match('herd') # True ``` **Solution :** ```python expr_reg = re.compile(r'\d+\.\d+ \d+\.\d+ \d+\.\d+ \d+\.\d+$') with open('GPS_data.txt', 'r') as in_file: coords = [] for line in in_file: if expr_reg.match(line): data_txt = line.split() data_float = [float(x) for x in data_txt] lat = minutes_vers_degres(data_float[1]) longi = minutes_vers_degres(data_float[2]) (zone, e, n) = LLUC.LLtoUTM(23, lat, -longi) coords.append([datal[0], e, n, datal[3]]) ... ``` ### GPS 5 Il faut cette fois-ci extraire les données des données brutes : ``` $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 = UTC of Position 2 = Latitude 3 = N or S 4 = Longitude 5 = E or W 6 = GPS quality indicator (0=invalid;1=GPS fix;2=Diff. GPS fix) 7 = Number of satellites in use [not those in view] 8 = Horizontal dilution of position 9 = Antenna altitude above/below mean sea level (geoid) 10 = Meters (Antenna height unit) 11 = Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. -=geoid is below WGS-84 ellipsoid) 12 = Meters (Units of geoidal separation) 13 = Age in seconds since last update from diff. reference station 14 = Diff. reference station ID# 15 = Checksum ``` **Solution :** ```python with open('GPS_data_raw.txt', 'r') as in_file: coords = [] for line in in_file: data_txt = line.split(',') try: data_float = [float(data_txt[i]) for i in [2, 4, 9]] lat =minutes_vers_degres(data_float[0]) if data_txt[3] == 'S': lat = -lat longi = minutes_vers_degres(data_float[1]) if data_txt[5] == 'W': longi = -longi (zone, e, n) = LLUC.LLtoUTM(23, lat, longi) coords.append([data_float[0], e, n, data_float[2]]) except Exception: print("Données non conformes : ", line) ``` ### Heavy Weather Un nouveau format vous est présenté mais il correspond à un type de données que votre ordinateur ne sait pas déchiffrer naturellement. On possède cependant des informations sur son chiffrement : ```txt Each row of data is stored in 56 byte chunks starting from the beginning of the file (no header). ROW OFFSET Type Name Unit ------ --------- ---------------- ----- 00 Double [8] Timestamp days from 12/30/1899 00:00:00 (GMT) 08 Float [4] Abs Pressure hectopascals (millibars) 12 Float [4] Relative Pressure hectopascals (millibars) 16 Float [4] Wind Speed meters/second 20 ULong [4] Wind Direction see below 24 Float [4] Wind Gust meters/second 28 Float [4] Total Rainfall millimeters 32 Float [4] New Rainfall millimeters 36 Float [4] Indoor Temp celsius 40 Float [4] Outdoor Temp celsius 44 Float [4] Indoor Humidity % 48 Float [4] Outdoor Humidity % 52 ULong [4] unknown - (Value is always 0) ``` Pour lire des fichiers binaires : ```python f = open("binary.bin", "rb") f.read(8) # Pour lire les 8 premiers bits ``` La librairie `struct` permet de déchiffrer les structures du langage C en Python : ```python import struct s = struct.Struct('<hhf') # short short float record = f.read(8) fields = s.unpack() record2 = s.pack(*fields) # l'étoile met la list 'à plat' ``` Programme : - Lire le fichier chunk par chunk - Corriger la température extérieure de 1.4 degrés Celsius **Solution :** ```python with open('binary_data.dat', 'rb') as src, \ open('binary_data_checked.dat', 'wb') as dst: try: # Record struct format s = struct.Struct('<d3fL7fL') while True: # Read a record from source file record = src.read(56) if len(record) != 56: break # Adjust data fields = s.unpack(record) adjusted = list(v+1.4 if i == 9 else v for i, v in enumerate(fields)) # Encode the record and write it to the dest file record = s.pack(*adjusted) dst.write(record) except Exception: # Your error handling here # Nothing for this example pass ``` ###### tags: `python`