UKOnline

Fichier

Un fichier est une abstraction d'une partie de la mémoire qui représente une information. Celle-ci peut prendre différentes formes : un document texte, une image, un son, une vidéo, un exécutable... Au plus bas niveau, toute information est stockée de la même manière, à savoir comme une séquence de bits ($0$ ou $1$) qu'il faut interpréter pour obtenir l'information de haut niveau représentée.

Plusieurs opérations peuvent être réalisées avec des fichiers. On peut tout d'abord en créer et en supprimer et lire et modifier leur contenu. Un fichier est également caractérisé par plusieurs informations que l'on peut obtenir, telles que son nom, sa taille, sa date de création et de dernière modification, ses permissions d'accès, etc. Toutes ces opérations peuvent être réalisées en Python, à l'aide de fonctions faisant essentiellement parties des modules os, os.path et shutil qui font le relais entre l'interpréteur Python et le système d'exploitation (Linux, Windows, MacOS...), qui est le seul à avoir directement accès aux disques. On ne va pas détailler toutes ces opérations ici, mais se concentrer sur la lecture et l'écriture de fichiers.

On distingue couramment deux types de fichier, qui seront manipulés à des niveaux différents :

  • Un fichier texte est constitué d'une séquence de caractères, permettant de stocker une chaine de caractères sur disque. Un fichier .py contenant le code source d'un programme Python est un exemple d'un tel fichier.
  • Un fichier binaire est constitué d'une séquence de bits, organisés en paquets de huit, appelés octets. Un fichier .png avec une image est un exemple d'un tel fichier.

La seule raison pour laquelle on différencie ces deux types de fichiers est car Python propose des fonctions spécifiques différentes permettant de facilement les manipuler. Dans l'absolu, il n'y a qu'un seul type de fichier, les fichiers texte étant également des fichiers binaires.

Créer et modifier un fichier

Pour manipuler un fichier, que ce soit en mode texte ou binaire, il y a trois principales étapes à suivre :

  • Il faut d'abord ouvrir le fichier désiré, en lecture ou en écriture. S'il s'agit d'un nouveau fichier, il doit être avant tout créé.
  • Une fois le fichier ouvert, on va pouvoir effectuer des opérations de lecture et d'écriture sur ce dernier.
  • Enfin, une fois que l'on a terminé, il faut fermer le fichier pour libérer les ressources allouées par le système d'exploitation.

Deux erreurs peuvent survenir lorsqu'on manipule un fichier. Tout d'abord, il se peut que le fichier que l'on tente d'ouvrir n'existe pas, dans lequel cas une erreur de type FileNotFoundError est générée. Ensuite, durant la lecture ou l'écriture, différentes situations d'erreur peuvent survenir comme le disque qui devient plein, l'utilisateur qui n'a pas les droits suffisants pour lire/écrire un fichier, etc. Dans toutes ces situations, une erreur de type IOError survient, signalant en fait une erreur d'entrée/sortie. Si on veut un programme robuste, il faudra les traiter à l'aide d'un try-except.

L'exception IOError est en fait une erreur générique d'entrée/sortie et on peut se limiter à gérer cette dernière. Néanmoins, il est parfois utile de gérer ses cas particuliers, parmi lesquels on a :

  • FileNotFoundError si le fichier n'existe pas ;
  • FileExistsError si le fichier existe déjà ;
  • PermissionError si le programme n'a pas les droits d'accès nécessaires sur le fichier ;
  • et IsADirectoryError si le fichier est en fait un dossier.

Chemin

Lorsqu'on veut créer un nouveau fichier ou en ouvrir un existant pour le lire ou le modifier, il faut préciser l'endroit où il est stocké, en spécifiant son chemin. Deux types de chemins sont possibles : relatif ou absolu.

Un chemin relatif décrit l'endroit où se trouve le fichier par rapport à l'endroit d'où est exécuté le programme. On peut connaitre le répertoire courant à l'aide de la fonction getcwd du module os :

Si on exécute ce programme sur une machine avec MacOS, on pourrait, par exemple, obtenir le résultat suivant :

/Users/combefis/Desktop

Un chemin relatif localise un fichier par rapport au répertoire courant. Si on indique juste un nom de fichier, cela revient à le chercher dans le répertoire courant. Si le chemin que l'on demande contient des répertoires, ils seront suivis à partir du répertoire courant. Enfin, on peut utiliser la notation spéciale ../ pour remonter d'un répertoire. Le tableau de la figure 1 reprend des chemins relatifs avec le chemin absolu correspondant, en supposant que l'on se trouve dans le répertoire courant montré ci-dessus.

Chemin relatif Chemin absolu
data.txt /Users/combefis/Desktop/data.txt
src/program.py /Users/combefis/Desktop/src/program.py
../image.png /Users/combefis/image.png
../movies/food.mp4 /Users/combefis/movies/food.mp4
Un chemin relatif se décrit par rapport au répertoire courant, la notation spéciale ../ permettant de remonter d'un répertoire.

Un chemin absolu donne donc la position d'un fichier à partir de la racine du disque. On peut transformer un chemin relatif en un absolu à l'aide de la fonction abspath du module os.path. De plus, on peut tester si un chemin correspond à un fichier qui se trouve réellement sur le disque avec la fonction exists du même module.

L'exemple suivant teste si un fichier référencé par un chemin relatif existe sur le disque, et affiche un message signalant l'existence ou non du fichier :

Si le fichier en question n'existe pas, on obtiendra le résultat suivant lors de l'exécution du programme :

Le fichier /Users/combefis/Desktop/data.txt n'existe pas.

Attention qu'il y a des différences sous Windows. Tout d'abord, la racine du disque est indiquée par un nom de lecteur, comme C:\, par exemple. De plus, le séparateur utilisé entre les répertoires est \ au lieu de /.