17. Lire et écrire des fichiers#

17.1. Lire un fichier#

Nous avons vu avec la création de la première carte, une fonction permettant de lire des données contenues dans un fichier texte.

def read_file(name):
    lines = ""
    with open(name) as f:
        lines = f.readlines()
    return lines

lines = read_file("datas/ligne4.txt")

Nous allons détaillons son fonctionnement et en particulier le mot clef with, mais commençons avec open. Cette fonction permet de lire un fichier. Elle prend en paramètre le chemin d’accès d’un fichier, l’adresse qui permet de le localiser sur l’ordinateur. Dans l’exemple ci-dessus c’est le fichier ligne4.txt qui est contenu dans le répertoire datas. Le chemin est donc datas/ligne4.txt où le caractère / marque séparation entre les sous-répertoires. Sous Windows, ce marqueur est historiquement \ mais Python accepte le marquer / qui fonctionne sur tous les systèmes d’exploitation. Il est donc à préférer.

Il existe deux types de chemins d’accès :

  • Le chemin absolu indique le chemin complet pour accéder à un fichier, en partant de la racine du système de fichiers (/ sur Unix, Linux ou OSX et une lettre de disque sous Windows). Par exemple : /Users/John/Documents/mon_fichier.txt.

  • Le chemin relatif : c’est un chemin d’accès qui indique le chemin pour accéder à un fichier en partant du répertoire courant (celui dans lequel se trouve le script Python qui utilise ce chemin d’accès). datas/ligne4.txt que l’on peut aussi noter ./datas/ligne4.txt. désigne le répertoire courant. On peut aussi remonter vers le répertoire père avec .. ou ../.. pour le grand père, etc.

Il est important de bien comprendre la différence entre ces deux types de chemins d’accès, car cela peut avoir une influence sur le fonctionnement de votre code. Si vous utilisez un chemin absolu dans un script et que vous déplacer le répertoire contenant votre projet, votre script ne sera pas en mesure de trouver le fichier ciblel et produira une erreur. En revanche, si vous utilisez un chemin relatif, votre script sera en mesure de trouver le fichier, car il commencera à chercher à partir du répertoire courant.

Une fois le fichier ouvert, la fonction readlines lit toutes les lignes du fichier et renvoie une liste de chaînes de caractères. La fonction readline lit une unique ligne du fichier et renvoie une chaîne de caractères se terminant par un retour à la ligne \n. Lorsque la fonction readline renvoie une chaîne vide "" (sans retour à la ligne), c’est que l’on a lu toutes les lignes.

with open(name) as f:
    while f: # True si le fichier a été ouvert correctement
        line = f.readline()
        print(line)
        if line == "":
            break 

Cette solution n’est pas très élégante. En général, on préfèrera utiliser une boucle pour. En Python, un fichier est un objet itérable, on peut donc s’en servir dans une boucle pour.

with open(name) as f:
    for line in f: 
        print(line)

17.2. Écrire un fichier#

Par défault, Python ouvre les fichiers en lecture, on ne peut rien écrire. On peut changer se comportement en précisant le mode d’ouverture. Il en existe deux pour l’écriture.

  • Le mode w, open(file_name, mode='w'). Il écrase le contenu du fichier s’il existe déjà ou crée un nouveau fichier sinon. Le pointeur est placé au début du fichier.

  • Le mode a, open(file_name, mode='a'). Il ouvre un fichier en écriture. Le pointeur est placé à la fin du fichier s’il existe, sinon un nouveau fichier est créé.

Avec la fonction write on peut alors écrire des chaînes de caractères dans le fichier : f.write("Une chaine").

17.3. Encodage#

Historiquement, seul les caractères anglophones étaient utilisés en informatique. On a donc décidé d’une manière d’encoder les caractères de l’alphabet anglais en binaire, le seul alphabet connu de nos ordinateur. Un problème est rapidement apparu quand il a fallu introduire les caractères provenant des autres alphabets car ils ont plus de caractères et qu’il fallait plus de bits pour le représenter… Une multitude d’encodages a donc émergé et cela pose toujours des problèmes.

Par exemple

  • avec l’encodage UTF-8, le caractère é est encodé avec les bits 1100001110101001 ;

  • avec l’encodage latin-1, ce sont uniquement 8 bits qui sont utilisés 11101001.

Un bon principe est d’utiliser comme encodage l’UTF-8 qui est relativement standard. On précise l’encodage au moment de l’ouverture du fichier : open(file_name, mode='w', encoding="utf8"). Pour l’écriture, ça ne pose que peu de problème puisque c’est au développeur de choisir.

À l’inverse, au moment d’ouvrir un fichier en lecture, cela peut être plus pénible. Beaucoup de fichier ne sont pas encodé en UTF-8. Lorsque cela arrive, on verra apparaitre dans les chaines qui sont lues des caractères étranges comme é. C’est le signe que l’encodage avec lequel on lit le fichier, n’est pas le même que celui avec lequel le fichier a été écrit. La plus part du temps, il suffira de parier que l’on a affaire à du latin-1 : open(file_name, mode='r', encoding="latin-1"). D’autres fois, cela ne fonctionnera pas et il faudra retrouver l’encodage utilisé.

Petite illustration des soucis d’encodage…

'On écrit ça dans un fichier.'.encode('utf8').decode('latin1')
'On écrit ça dans un fichier.'

17.4. Mot clef with#

La dernière chose qu’il nous reste à voir est le mot clef with. Ce mot clef permet de mettre en place ce que l’on appelle des context managers. Sans rentrer trop dans les détails, le mot clef with définit un block de code qui débute au moment où le fichier est ouvert et qui se termine au moment où le fichier cesse d’être utilisé et donc au moment où l’on pourra refermer le fichier. Cette fermeture est faite implicitement par Python.

On pourrait tout a fait se passer du mot clef with. Dans ce cas, on obtiendrait le code suivant.

f = open(file_name, mode="w")
f.write("Une chaine)
...

Mais attention, il faudrait refermer explicitement le fichier.

f.close()

Cette fermeture est importante car si le programme bugue et s’arrête alors que le fichier est toujours ouvert, il est possible que des données qui devaient être écrites ne le soit finalement pas.

Il est donc vivement recommander d’utiliser la solution utilisant with dans vos codes.

17.5. Exercice#

Modifier le programme qui génère la carte des plus grandes villes de France afin de les stocker dans un fichier avec toutes leurs informations.