Travailler avec les I/O de fichiers en Python
- 2021-08-10
- Publié par : Christophe DELEUZE
- Catégorie : Python
Je vous propose de découvrir et réviser avec moi les bases du travail avec des fichiers en Python. Nous verrons ensemble comment lire des fichiers, comment y écrire des données, comment faire des recherches dans des fichiers et pourquoi les fichiers doivent être fermés après utilisation.
La lecture et l’écriture de fichiers dans n’importe quel langage de programmation est une fonctionnalité importante. Sans elle, toutes les variables et informations seraient uniquement stockées dans une mémoire volatile dont le contenu serait systématiquement perdu à chaque arrêt de l’ordinateur ou du programme. Toutefois, lorsque vous enregistrez des données dans un fichier permanent, vous pouvez les récupérer ultérieurement sans souci.
Fichiers binaires vs fichiers texte en Python
Python gère deux types de fichiers distincts : les fichiers binaires et les fichiers texte. Connaitre la différence entre les deux est important en raison de la façon dont ils sont traités.
Les fichiers binaires
La plupart des fichiers que vous utilisez au cours de votre utilisation normale d’un ordinateur sont en fait des fichiers binaires, pas du texte. Par exemple, un fichier .doc de Microsoft Word est en fait un fichier binaire, même s’il ne contient que du texte. D’autres exemples de fichiers binaires incluent :
- Fichiers image comprenant .jpg, .png, .bmp, .gif, … ;
- Fichiers de base de données comprenant .mdb, .frm, et .sqlite ;
- Documents comprenant .doc, .xls, .pdf, … .
C’est parce que ces fichiers ont tous des exigences de traitements spécifiques qui nécessitent un type de logiciel dédié pour les ouvrir. Par exemple, vous avez besoin d’Excel pour ouvrir un fichier .xls et d’un programme de base de données pour ouvrir un fichier .sqlite.
Les fichiers textes
Un fichier texte, en revanche, n’a pas de codage spécifique et peut être ouvert par un éditeur de texte standard sans aucune manipulation particulière. Néanmoins, chaque fichier texte doit respecter un ensemble de règles :
- Les fichiers texte doivent être lisibles tels quels. Ils peuvent (et contiennent souvent) beaucoup d’encodages spéciaux, en particulier en HTML ou dans d’autres langages de balisage, mais vous serez toujours en mesure de le lire ;
- Les données d’un fichier texte sont organisées par lignes. Dans la plupart des cas, chaque ligne est un élément distinct, qu’il s’agisse d’une ligne d’instruction ou d’une commande.
De plus, les fichiers texte ont tous un caractère invisible à la fin de chaque ligne qui permet à l’éditeur de texte de savoir qu’il doit y avoir une nouvelle ligne. Lorsque vous interagissez avec ces fichiers via la programmation, vous pouvez tirer parti de ce caractère qui est : n.
Où trouver les outils d'I/O de fichiers de Python
En Python, vous n’avez pas à vous soucier d’importer des bibliothèques externes spécifiques pour travailler avec des fichiers. Python est livré nativement avec les outils et utilitaires d’I/O (Input/Output) de fichiers qui font partie intégrante du langage de base. On appelle I/O de fichier (E/S en français pour Entrées/Sorties) tout ce qui concerne la lecture et l’écriture de fichiers.
Dans d’autres langages comme le C++, pour travailler avec des fichiers, vous devez activer les outils d’I/O de fichiers en incluant la bonne dépendance, par exemple à l’aide de #include <fstream>. Et si vous codez en Java, vous avez besoin de la déclaration import java.io.*. Avec Python, ce n’est pas nécessaire.
Au lieu de cela, Python a un ensemble intégré de fonctions qui gère tout ce dont vous avez besoin pour lire et écrire dans des fichiers. Nous allons maintenant les examiner de plus près.
Ouvrir un fichier
La première fonction que vous devez connaitre est open(). Cette fonction renvoi un objet fichier. Son utilisation de base est la suivante et comprend 2 paramètres importants à connaitre qui sont filename et mode :
file_object = open(filename, mode)
Le paramètre filename doit recevoir le nom du fichier que vous souhaitez manipuler, avec l’extension de fichier incluse. Autrement dit, si vous avez un fichier texte qui se nomme salut.txt, votre nom de fichier ne sera pas "salut", mais "salut.txt". Vous pouvez également spécifier le chemin complet de la localisation du fichier, tel que C:….salut.txt, si vous utilisez Windows.
Attention, quand une barre oblique inverse est présente dans une chaine de caractère, celle-ci est systématiquement interprétée comme un caractère d’échappement en Python et non comme la valeur littérale de . Il y a donc un problème ici, car nous voulons la valeur littérale du caractère, or, nous allons avoir un échappement de caractère.
Heureusement, Python a deux façons de gérer cela. La première consiste à utiliser des doubles barres obliques inverses comme ceci : "C:\....\salut.txt". La seconde consiste à utiliser des barres obliques : "C:/..../salut.txt".
Le paramètre mode de la fonction open() indique à Python ce que vous voulez faire avec le fichier. Il existe plusieurs modes que vous pouvez spécifier lorsque vous traitez des fichiers texte :
'w'– Mode Écriture : Ce mode est utilisé lorsque le fichier doit être modifié et des informations modifiées ou ajoutées. Gardez à l’esprit que cela efface le fichier existant pour en créer un nouveau. Le pointeur de fichier est placé au début du fichier ;'r'– Mode Lecture : Ce mode est utilisé lorsque les informations contenues dans le fichier sont uniquement destinées à être lues et non modifiées de quelque manière que ce soit. Le pointeur de fichier est placé au début du fichier ;'a'– Mode Ajout : Ce mode ajoute automatiquement des informations à la fin du fichier. Le pointeur de fichier est placé à la fin du fichier ;'r+'– Mode Lecture et Écriture : Ceci est utilisé lorsque vous apportez des modifications au fichier et lisez des informations à partir de celui-ci. Le pointeur de fichier est placé au début du fichier ;'a+'– Mode Ajout et Lecture : un fichier est ouvert pour permettre l’ajout de données à la fin du fichier et permet également à votre programme de lire les informations. Le pointeur de fichier est placé à la fin du fichier.
Lorsque vous utilisez des fichiers binaires, vous utiliserez les mêmes spécificateurs de mode. Cependant, vous ajoutez b à la fin. Ainsi, un spécificateur de mode d’écriture pour un fichier binaire est wb. Les autres sont rb, ab, r+b et a+b respectivement.
En complément, dans Python 3, un nouveau mode a été ajouté :
x– Mode de création exclusif : Ce mode est utilisé exclusivement pour créer un fichier. Si un fichier du même nom existe déjà, l’appel de fonction échouera.
Ouvrir un fichier et définir le mode d'accès
Voyons par un exemple comment ouvrir un fichier et définir le mode d’accès.
Lorsque vous utilisez la fonction open(), vous attribuez généralement son résultat à une variable. Étant donné un fichier nommé salut.txt, le code approprié pour ouvrir le fichier en lecture et en écriture sera le suivant :
file_object = open("salut.txt", "r+")
Ce code permet de créer un objet appelé file_object qui pourra ensuite être manipulé à l’aide de ses méthodes.
Nous avons utilisé le mode d’accès 'r+' dans cet exemple de code qui indique à Python que nous voulons ouvrir le fichier pour la lecture et l’écriture. Cela nous donne beaucoup de flexibilité, mais souvent, vous voudrez peut-être restreindre votre programme à la lecture ou à l’écriture dans un fichier et c’est là que les autres modes seront utiles.
Fermer un fichier
Savoir comment fermer un fichier après l’avoir manipulé est un point important à maitriser. Fermer un fichier permet de libérer les ressources système que votre programme utilise à des fins d’I/O (Input/Output). Lorsque vous écrivez un programme qui a des contraintes d’espace ou de mémoire, cela vous permet de gérer efficacement vos ressources.
De plus, la fermeture d’un fichier vous garantira que toutes les données en attente seront écrites sur le système de stockage sous-jacent, par exemple, votre lecteur de disque local. En fermant explicitement le fichier, vous vous assurerez que toutes les données mises en mémoire tampon contenues dans la mémoire seront supprimées et écrites dans le fichier.
La méthode à utiliser pour fermer un fichier en Python est simplement .close(). En utilisant l’objet fichier file_object que nous avons créé dans l’exemple précédent, l’appel de la méthode pour fermer le fichier sera :
file_object.close()
Après avoir fermé un fichier, vous ne pouvez plus y accéder jusqu’à ce que vous le rouvriez à une date ultérieure. Tenter de lire ou d’écrire dans un objet fichier fermé lèvera une exception ValueError :
>>> f = open("/tmp/myfile.txt", "w")
>>> f.close()
>>> f.read()
Traceback (most recent call last):
File "<input>", line 1, in <module>
f.read()
ValueError: I/O operation on closed file.
En Python, la meilleure pratique pour ouvrir et fermer des fichiers est d’utiliser l’instruction (mot-clé) with. Cette instruction ferme le fichier automatiquement une fois le bloc de code imbriqué terminé :
with open("salut.txt", "r+") as file_object:
# Le fichier objet est maintenant ouvert
# Par conséquent je peux manipuler le fichier, ici je le lis :
file_object.read()
# Le fichier objet est maintenant fermé
# Faire d'autres trucs...
Toutefois, si vous n’utilisez ni with, ni la méthode .close() pour fermer un fichier, Python fermera et détruira quand même automatiquement l’objet fichier via le ramasse-miettes intégré. Cependant, selon votre code, ce ramasse-miettes peut s’exécuter à n’importe quel moment.
Il est donc recommandé de toujours utiliser le mot-clé with afin de contrôler quand le fichier sera fermé, c’est-à-dire après la fin de l’exécution du bloc de code interne.
Travailler avec des objets de fichier
Une fois que vous avez ouvert un fichier avec succès, vous pouvez utiliser des méthodes intégrées pour gérer le nouvel objet fichier. Vous pouvez y lire des données ou y écrire de nouvelles données. Il existe également d’autres opérations telles que le déplacement du “pointeur de lecture/écriture”, qui détermine l’endroit à partir duquel les données du fichier seront lues et écrites. Nous y reviendrons un peu plus tard dans le tutoriel.
Lire des données à partir d'un fichier
Pour lire le contenu d’un fichier, il faut utiliser la méthode .read(). Par défaut, cette méthode lira l’intégralité du fichier et l’affichera sur la console sous forme de chaine (en mode texte) ou d’objets octets (en mode binaire).
Cependant, vous devez être prudent lorsque vous utilisez cette méthode. En effet, si le fichier que vous lisez est plus volumineux que votre mémoire disponible, vous ne pourrez pas accéder à l’intégralité du fichier en une seule fois. Dans un cas comme celui-ci, vous devrez utiliser le paramètre size pour le diviser en plusieurs morceaux que votre mémoire pourra gérer.
Le paramètre size indique à la méthode .read(size) combien d’octets dans le fichier doivent être retournés à l’affichage. Supposons donc que notre fichier salut.txt contienne le texte suivant :
Donnée de la ligne 1
Donnée de la ligne 2
Donnée de la ligne 3
Ensuite, si vous avez écrit le programme suivant en Python :
with open("salut.txt", "r+") as file_object:
print("Le nom du fichier est: ", file_object.name)
line = file_object.read()
print(line)
Vous obtiendrez cette sortie :
Le nom du fichier est: salut.txt
Donnée de la ligne 1
Donnée de la ligne 2
Donnée de la ligne 3
En revanche, si vous modifiez la troisième ligne pour dire :
line = file_object.read(6)
Vous obtiendrez la sortie suivante :
Le nom du fichier est: salut.txt
Donnée
Comme vous pouvez le voir, l’opération de lecture n’a lu que les données du fichier jusqu’à la position 6, ce que correspond à ce que nous avons passé à l’appel de la méthode .read() ci-dessus. De cette façon, vous pouvez limiter la quantité de données lues à partir d’un fichier en une seule fois.
Si vous lisez à nouveau à partir du même objet fichier, il continuera à lire les données là où vous vous étiez arrêté. De cette manière, vous pouvez traiter un gros fichier en plusieurs parties plus petites.
Lecture de fichiers texte ligne par ligne avec readline()
Vous pouvez également analyser les données d’un fichier en le lisant ligne par ligne. Cela peut vous permettre de parcourir un fichier entier ligne par ligne, en avançant uniquement lorsque vous le souhaitez, ou de voir une ligne spécifique.
La méthode .readline() renvoie par défaut la première ligne du fichier. Mais en modifiant le paramètre entier size, vous pouvez obtenir n’importe quelle ligne de votre fichier dont vous avez besoin.
Par exemple :
with open("salut.txt", "r+") as file_object:
print("Le nom du fichier est: ", file_object.name)
line_data = file_object.readline()
print(line_data)
Cela renverrait la sortie suivante :
Le nom du fichier est: salut.txt
Donnée de la ligne 1
Vous pouvez appeler .readline() à plusieurs reprises pour lire des lignes de texte supplémentaires à partir du fichier.
Une méthode similaire est .readlines() (notez le pluriel), qui renvoie une liste de toutes les lignes du fichier. Si vous avez appelé :
print(file_object.readlines())
Vous obtiendrez la sortie suivante :
['Donnée de la ligne 1', 'Donnée de la ligne 2', 'Donnée de la ligne 3']
Comme vous pouvez le voir, cela lit tout le fichier en mémoire et le divise en plusieurs lignes. Cela ne fonctionne cependant qu’avec les fichiers texte. Un fichier binaire n’étant qu’un paquet de données, il ne connait pas vraiment le concept de ligne.
Traitement d'un fichier texte entier ligne par ligne
Le moyen le plus simple de traiter un fichier texte entier ligne par ligne en Python consiste à utiliser une simple boucle for :
with open("salut.txt", "r+") as file_object:
for line in file_object:
print(line)
Cela nous donnera la sortie suivante :
Donnée de la ligne 1
Donnée de la ligne 2
Donnée de la ligne 3
Cette approche est très économe en mémoire, car nous allons lire et traiter chaque ligne individuellement. Cela signifie que notre programme n’a jamais besoin d’avoir tout le fichier en mémoire pour le lire. De plus, l’utilisation de readline() sous-jacente à cette façon de lire un fichier est un moyen confortable et efficace de traiter un gros fichier texte en plus petits morceaux.
Écrire dans un fichier en utilisant .write()
Les fichiers ne serviraient à rien si vous ne pouviez pas y écrire de données.
N’oubliez pas que lorsque vous créez un nouvel objet fichier, Python créera le fichier s’il n’en existe pas déjà un. Lors de la création d’un fichier pour la première fois, vous devez utiliser les modes a+ ou w+.
Il est souvent préférable d’utiliser le mode a+ car les données seront ajoutées par défaut à la fin du fichier. L’utilisation w+ effacera toutes les données existantes dans le fichier et vous donnera une ardoise vierge à partir de laquelle commencer.
La méthode par défaut d’écriture dans un fichier en Python est .write(data). Le paramètre data est obligatoire et il doit être fournis sous forme d’une chaine de caractères. Par exemple, vous pouvez ajouter une nouvelle ligne à notre fichier salut.txt en utilisant le code suivant :
file_object.write("Donnée de la ligne 4n")
Le n agit comme l’indicateur de nouvelle ligne, déplaçant les écritures suivantes vers la ligne suivante.
Si vous voulez écrire quelque chose qui n’est pas une chaine dans un fichier texte, comme une série de nombres, vous devez préalablement les convertir en chaines à l’aide de la fonction de conversion str().
Par exemple, si vous souhaitez ajouter les nombres entiers 1234, 5678, 9012 au fichier salut.txt, procédez comme suit. Tout d’abord, vous convertissez chaque entier en chaine, puis vous écrivez chaque chaine dans votre objet fichier :
entiers = [1234, 5678, 9012]
with open("salut.txt", "a+") as file_object:
for entier in entiers:
str_entier = str(entier)
file_object.write(str_entier)
file_object.write("n")
Recherches dans des fichiers : déplacement du pointeur de lecture/écriture
N’oubliez pas que lorsque vous écrivez en utilisant le mode a+, votre pointeur de fichier se trouve toujours à la fin du fichier. Donc, en prenant le code ci-dessus, à chaque fois que vous utiliserez la méthode .write(), celle-ci déplacera le pointeur après la ligne écrite, ce qui aura pour conséquence que le pointeur sera toujours localisé à la fin du fichier.
Ce que vous devez faire ensuite, c’est replacer le pointeur au début du fichier. La façon la plus simple de le faire est d’utiliser la méthode .seek(offset, from_what). Dans cette méthode, vous placez le pointeur à un endroit spécifique.
L’offset est le nombre de caractères du paramètre from_what. Le paramètre from_what a trois valeurs possibles :
0– indique le début du fichier ;1– indique la position actuelle du pointeur ;2– indique la fin du fichier.
Lorsque vous travaillez avec des fichiers texte (ceux qui ont été ouverts sans "b" dans le mode), vous pouvez seulement vous contenter d’utiliser la valeur par défaut 0 (.seek(0)) qui vous amènera au début du fichier ou .seek(0, 2), qui vous amènera à la fin du fichier.
Donc en utilisant file_object.seek(3, 0) sur notre fichier salut.txt, vous placerez le pointeur sur le 4ᵉ caractère (rappelez-vous que Python commence à compter à partir de 0). Si vous utilisez une boucle for pour afficher les lignes, alors vous obtiendrez la sortie suivante :
née de la ligne 1
Donnée de la ligne 2
Donnée de la ligne 3
Si vous souhaitez vérifier la position actuelle du pointeur, vous pouvez utiliser la méthode .tell() qui renvoie une valeur décimale pour l’emplacement du pointeur dans le fichier actuel. Si nous voulons connaitre la longueur de notre fichier actuel file_object, nous pouvons utiliser le code suivant :
with open("salut.txt", "a+") as file_object:
print(file_object.tell())
Cela donnera une valeur de retour qui sera la taille du fichier.
Modification d'un fichier texte
Il viendra un moment où vous devrez modifier un fichier existant plutôt que de simplement y ajouter des données. Vous ne pouvez pas simplement utiliser le mode w+ pour le faire. N’oubliez pas que le mode w écrasera complètement le fichier, donc même avec l’utilisation de .seek(), vous ne pourrez pas le faire. Et a+ insèrera toujours des données à la fin du fichier.
La façon la plus simple de le faire consiste à extraire le fichier en entier et à créer une liste ou un tableau de données avec celui-ci. Une fois la liste créée, vous pouvez utiliser la méthode list.insert(i, x) pour insérer vos nouvelles données. Une fois la nouvelle liste créée, vous pouvez ensuite la joindre à nouveau et la réécrire dans votre fichier.
N’oubliez pas que pour list.insert(i, x), i correspond à un entier qui représente un index dans la liste. Les données de x sont alors placées à l’index indiqué par i.
Par exemple, en utilisant notre fichier salut.txt, disons que nous devons insérer la ligne de texte "Ceci va entre les lignes 1 et 2" entre la première et la deuxième ligne. Le code pour le faire sera :
# J'ouvre le fichier en lecture seule
with open("salut.txt", "r") as file_object:
file_object_contents = file_object.readlines()
# J'ajoute une ligne à l'index 1 de la liste (ce qui correspondra à la 2ème ligne du fichier)
file_object_contents.insert(1, "Ceci va entre les lignes 1 et 2n")
# Je réouvre le fichier en écriture seule pour écraser l'ancien fichier
with open("salut.txt", "w") as file_object:
file_objectContents = "".join(file_object_contents)
file_object.write(file_object_contents)
Une fois ce code exécuté, nous pouvons procéder comme suit pour lire notre fichier :
with open("salut.txt", "r") as file_object:
for line in file_object:
print(line)
Vous obtiendrez alors la sortie suivante :
Donnée de la ligne 1
Ceci va entre les lignes 1 et 2
Donnée de la ligne 2
Donnée de la ligne 3
Voilà, nous avons démontré comment modifier un fichier texte existant en Python, en insérant une nouvelle ligne de texte exactement à l’endroit souhaité.
Le mot de la fin
Dans ce tutoriel, vous avez appris les bases de la gestion des fichiers en Python. Voici l’éventail des sujets que nous avons abordés :
- La différence entre les fichiers binaires et les fichiers texte ;
- Quels sont les fonctions et outils d’I/O de fichiers intégrés à Python ;
- Comment ouvrir et fermer des fichiers ;
- Les différentes manières de lire les données d’un fichier ;
- Comment écrire des données dans un objet fichier ;
- Rechercher des données dans un fichier et déplacer le pointeur de lecture/écriture ;
- Modifier un fichier texte existant.
Malgré ce tutoriel assez long, nous n’avons fait qu’effleurer la surface ici. Comme pour tout ce qui concerne la programmation, il y a beaucoup plus à apprendre et je vous invite à vous reporter à la documentation officielle pour pousser votre apprentissage.
Dans tous les cas, j’espère que cet article vous aura plus et je vous dis à bientôt dans les commentaires.