P3.4 Gestion de fichiers

Utilisez des fichiers

Dans cette partie vous allez utiliser l'environnement de développement de votre choix (EduPython, Thonny, Anaconda, Pyzo...).
Vous allez gérer des fichiers dans des répertoires.
Si vous êtes au lycée (et vous pourrez faire de même chez vous), il est probable que vous allez travailler sur votre clef USB et que celle-ci est installée sur D:\

Avant de commencer

Nous allons beaucoup travailler sur des répertoires et des fichiers, autrement dit sur votre disque ou clef ou autre support de stockage de données. Donc je vais vous donner quelques informations générales avant de commencer pour que, malgré vos différents systèmes et configurations, vous puissiez essayer les instructions que je vais vous montrer.

Mais d'abord, pourquoi lire ou écrire dans des fichiers ?

Peut-être que vous ne voyez pas trop l'intérêt de savoir lire et écrire dans des fichiers, hormis quelques applications de temps à autre. Mais souvenez-vous que, quand vous fermez votre programme, aucune de vos variables n'est sauvegardée. Or, les fichiers peuvent être, justement, un excellent moyen de garder les valeurs de certains objets pour pouvoir les récupérer quand vous rouvrirez votre programme. Par exemple, un petit jeu peut enregistrer les scores des joueurs.

Si, dans notre TP ZCasino, nous avions pu enregistrer la somme que nous avions en poche au moment de quitter le casino, nous aurions pu rejouer sans repartir de zéro.

AVANT DE COMMENCER

Il faut créer un répertoire JUPYTER sur votre clef usb (gardez les majuscules).Nous considèrerons ce repertoire D:\JUPYTER comme la racine (le point de départ).
Créez ensuite un répertoire lireEcrireFichier dans le répertoire JUPYTER.

SE REPERER

Lancez Edupython et saisir dans la console :

>>>import os
>>>print os.getcwd()
Vous obtenez par exemple :

'C:/users/JLT/Documents'

(Ce ne sera sans doute pas celà pour vous, mais cette commande indique dans quel répertoire que vous travaillez en ce moment).

Je vous conseille, que vous soyez sous Windows ou non, d'utiliser le symbole / pour décrire un chemin.

Vous pouvez utiliser, en le doublant, l'antislash \\ mais, si vous oubliez de le doubler, vous aurez des erreurs. Je vous conseille donc d'utiliser le slash /, cela fonctionne très bien même sous Windows.

Quand vous lancez un programme Python directement, par exemple en faisant un double-clic dessus, le répertoire courant est celui d'où vous lancez le programme.

Par exemple, Si vous avez un fichier mon_programme.py contenu sur le disqueC:/users/Bureau, le répertoire de travail courant quand vous lancerez le programme sera C:/users/Bureau.

Chemins relatifs et absolus

Pour décrire l'arborescence d'un système, on a deux possibilités :

  • les chemins absolus ;
  • les chemins relatifs.

Le chemin absolu

Quand on décrit une cible (un fichier ou un répertoire) sous la forme d'un chemin absolu, on décrit la suite des répertoires menant au fichier. Sous Windows, on partira du nom de volume (C:\,D:\…). Sous les systèmes Unix, ce sera plus vraisemblablement depuis /.

Par exemple, sous Windows, si on a un fichier nomméfic.txt, contenu dans un dossiertest, lui-même présent sur le disqueC:, le chemin absolu menant à notre fichier seraC:\test\fic.txt.

Le chemin relatif

Quand on décrit la position d'un fichier grâce à un chemin relatif, cela veut dire que l'on tient compte du dossier dans lequel on se trouve actuellement. Ainsi, si on se trouve dans le dossierC:\testet que l'on souhaite accéder au fichierfic.txtcontenu dans ce même dossier, le chemin relatif menant à ce fichier sera tout simplementfic.txt.

Maintenant, si on se trouve dansC:, notre chemin relatif sera test/fic.txt.

Quand on décrit un chemin relatif, on utilise parfois le symbole..qui désigne le répertoire parent. Voici un nouvel exemple :

  • C:
    • test
      • rep1
        • fic1.txt
      • rep2
        • fic2.txt
        • fic3.txt

C'est dans notre dossiertestque tout se passe. Nous avons deux sous-répertoires nommésrep1etrep2. Dansrep1, nous avons un seul fichier :fic1.txt. Dansrep2, nous avons deux fichiers :fic2.txtetfic3.txt.

Si le répertoire de travail courant estrep2et que l'on souhaite accéder àfic1.txt, notre chemin relatif sera donc..\rep1\fic1.txt.

J'utilise ici des antislashs parce que l'exemple d'arborescence est un modèle Windows et que ce sont les séparateurs utilisés pour décrire une arborescence Windows. Mais, dans votre code je vous conseille quand même d'utiliser un slash(/).

Nous allons commencer à lire avant d'écrire dans un fichier. Pour l'exemple donc, je vous invite à créer :

1- Un répertoire Data dans D:/JUPYTER/lireEcrireFichier

2- un nouveau fichier dans ce répertoire. Je suis en manque flagrant d'inspiration, je vais donc l'appelerfichier.txt. A l'aide d'un éditeur sans mise en forme (tel que le bloc-notes Windows, ou notepad++, mais veillez à enregistrer au format txt ) écrivons dans ce fichier :

C'est le contenu du fichier. Spectaculaire non ?

la fonction open

Dans edupython

Vous devez maintenant, dans python, changer de répertoire de travail courant.
Pour cela, vous devez utiliser une fonction du module os, qui s'appelle chdir (abréviantion de Change Directory).

>>> os.chdir("D:/JUPYTER/lireEcrireFichier")
>>>

Lecture et écriture dans un fichier

Ouverture du fichier

D'abord, il nous faut ouvrir le fichier avec Python. On utilise pour ce faire la fonctionopen, disponible sans avoir besoin de rien importer. Elle prend en paramètre :

  • le chemin (absolu ou relatif) menant au fichier à ouvrir ;
  • le mode d'ouverture.

Le mode est donné sous la forme d'une chaîne de caractères. Voici les principaux modes :

  • 'r': ouverture en lecture (Read).
  • 'w': ouverture en écriture (Write). Le contenu du fichier est écrasé. Si le fichier n'existe pas, il est créé.
  • 'a': ouverture en écriture en mode ajout (Append). On écrit à la fin du fichier sans écraser l'ancien contenu du fichier. Si le fichier n'existe pas, il est créé.

Il existe d'autres modes, mais pour nous cela sera suffisant.

Ici nous souhaitons lire le fichier. Nous allons donc utiliser le mode'r'.

>>> mon_fichier = open("Date/fichier.txt", "r")
>>> mon_fichier
<_io.TextIOWrapper name='fichier.txt' encoding='cp1252'>
>>> type(mon_fichier)
<class '_io.TextIOWrapper'>
>>>
L'encodage précisé quand on affiche le fichier dans l'interpréteur peut être très différent suivant votre système. Ici, je suis dans l'interpréteur Python dans Windows et l'encodage choisi est donc un encodage Windows propre à la console. Ne soyez pas surpris s'il est différent chez vous. Nous verrons un peu plus loin comment choisir un encodage plus adapté.

La fonctionopencrée donc un fichier. Elle renvoie un objet de la classeTextIoWrapper. Par la suite, nous allons utiliser des fonctions liées à cette classe pour interagir avec le fichier.

Le type de l'objet doit vous surprendre quelque peu. Cela aurait très bien pu être un typefileaprès tout. En fait,openpermet d'ouvrir un fichier, maisTextIoWrapperest utilisé dans d'autres circonstances, pour afficher du texte à l'écran par exemple. Bon, cela ne nous concerne pas trop ici, je ne vais pas m'y attarder.

Fermer le fichier

N'oubliez pas de fermer un fichier après l'avoir ouvert. Si d'autres applications, ou d'autres morceaux de votre propre code, souhaitent accéder à ce fichier, ils ne pourront pas car le fichier sera déjà ouvert. C'est surtout vrai en écriture, mais prenez de bonnes habitudes. La méthode à utiliser estclose:

>>> mon_fichier.close()
>>>

Lire l'intégralité du fichier

Pour ce faire, on utilise la méthodereadde la classeTextIoWrapper. Elle renvoie l'intégralité du fichier :

>>> mon_fichier = open("fichier.txt", "r")
>>> contenu = mon_fichier.read()
>>> print(contenu)
C'est le contenu du fichier. Spectaculaire non ?
>>> mon_fichier.close()
>>>
Quoi de plus simple ? La méthodereadrenvoie tout le contenu du fichier, que l'on capture dans une chaîne de caractères. Notre fichier ne contient pas de saut de ligne mais, si c'était le cas, vous auriez dans votre variablecontenules signes\ntraduisant un saut de ligne.

Maintenant que vous avez une chaîne, vous pouvez naturellement tout faire : la convertir, tout entière ou en partie… bref, tout est possible.

Écriture dans un fichier

Bien entendu, il nous faut ouvrir le fichier avant tout. Vous pouvez utiliser le modewou le modea. Le premier écrase le contenu éventuel du fichier, alors que le second ajoute ce que l'on écrit à la fin du fichier. À vous de voir en fonction de vos besoins. Dans tous les cas, ces deux modes créent le fichier s'il n'existe pas.

Écrire une chaîne

Pour écrire dans un fichier, on utilise la méthode write en lui passant en paramètre la chaîne à écrire dans le fichier. Elle renvoie le nombre de caractères qui ont été écrits. On n'est naturellement pas obligé de récupérer cette valeur, sauf si on en a besoin.

Voici un exemple : nous allons d'abord écrire 2 lignes dans le fichier, puis les relire :

>>> mon_fichier = open("fichier.txt", "w") # Argh j'ai tout écrasé !
>>> mon_fichier.write("Premier test d'écriture dans un fichier via Python")

50
>>> mon_fichier.write('ligne2')
6
>>> mon_fichier.close()
>>> mon_fichier = open("fichier.txt", "r") 
>>> c=mon_fichier.read()
>>> c
"Premier test d'écriture dans un fichier via Pythonligne2"
>>> 
Vous pouvez vérifier que votre fichier contient bien le texte qu'on y a écrit. Vous avez de fortes chance d'observer 2 défauts :

  • L'accent de écriture est mal transcrit
  • La deuxième ligne est mis au bout de la première

encodage et caractères de fin de ligne

Pour le problème des accents, c'est un problème d'encodage du texte, et nous aborderons plus tard cette question. Pour y remédier, lors de l'ouverture (en écriture comme en lecture), vous aller toujours prend l'habitude de préciser l'encodage avec l'option encoding='utf-8'

Pour le problème de retour à la ligne, il suffit d'ajouter un caractère de fin de ligne lors de l'écriture : \n.

Mais ce caractère devra alors être pris en compte car il sera relu....

>>> mon_fichier = open("fichier.txt", "w", encoding='utf-8') 
mon_fichier.write("Premier test d'écriture dans un fichier via Python\n")
51
>>> mon_fichier.write('ligne2'+'\n')
7
>>> mon_fichier.close()
>>> mon_fichier = open("fichier.txt", "r" , encoding='utf-8') 
>>> c=mon_fichier.read()
>>> c
"Premier test d'écriture dans un fichier via Python\nligne2\n"
>>> print(c)
Premier test d'écriture dans un fichier via Python
ligne2
Vous pouvez regarder dans fichier.txt, vous verrez que les \n n'apparaissent pas et que le texte est bien sur 2 lignes.

ecrire autre chose que du texte

Écrire d'autres types de données

La méthodewriten'accepte en paramètre que des chaînes de caractères. Si vous voulez écrire dans votre fichier des nombres, des scores par exemple, il vous faudra les convertir en chaîne avant de les écrire et les convertir en entier après les avoir lus.

la méthode with (recommandée)

Le mot-clé with

Ne désespérez pas, il ne nous reste plus autant de mots-clés à découvrir… mais quelques-uns tout de même. Et même certains dont je ne parlerai pas…

On n'est jamais à l'abri d'une erreur. Surtout quand on manipule des fichiers. Il peut se produire des erreurs quand on lit, quand on écrit… et si l'on n'y prend pas garde, le fichier restera ouvert.

Comme je vous l'ai dit, c'est plutôt gênant et cela peut même être grave. Si votre programme souhaite de nouveau utiliser ce fichier, il ne pourra pas forcément y accéder, puisqu'il a déjà été ouvert.

Il existe un mot-clé qui permet d'éviter cette situation :with. Voici sa syntaxe :

with open(mon_fichier, mode_ouverture) as variable:
    # Opérations sur le fichier
On trouve dans l'ordre :

  • Le mot-clé with, prélude au bloc dans lequel on va manipuler notre fichier. On peut trouver with dans la manipulation d'autres objets mais nous ne le verrons pas ici.
  • Notre objet. Ici, on appelleopenqui va renvoyer un objetTextIOWrapper(notre fichier).
  • Le mot-cléasque nous avons déjà vu dans le mécanisme d'importation et dans les exceptions. Il signifie toujours la même chose : « en tant que ».
  • Notre variable qui contiendra notre objet. Si la variable n'existe pas, Python la crée.

Un exemple :

>>> with open('fichier.txt', 'r') as mon_fichier:
...     texte = mon_fichier.read()
... 
>>>
Cela ne veut pas dire que le bloc d'instructions ne lèvera aucune exception (erreur).

Cela signifie simplement que, si une exception se produit, le fichier sera tout de même fermé à la fin du bloc.

Le mot-cléwithpermet de créer un "context manager" (gestionnaire de contexte) qui vérifie que le fichier est ouvert et fermé, même si des erreurs se produisent pendant le bloc. Vous verrez plus loin d'autres objets utilisant le même mécanisme.

Vous pouvez appelermon_fichier.closedpour vérifier que le fichier est refermé. Si le fichier est fermé,mon_fichier.closedvaudraTrue.

Il est inutile, par conséquent, de fermer le fichier à la fin du blocwith. Python va le faire tout seul, qu'une exception soit levée ou non. Je vous encourage à utiliser cette syntaxe, elle est plus sûre et plus facile à comprendre.

lire ligne par ligne

Lire tout le fichier d'un seul bloc n'est pas forcément idéal, nous allons envisager d'autres façon de lire, ligne par ligne. Pour cela on aura avantage à utiliser la méthode with

with open('fichier.txt', 'r' , ecoding='utf-8') as mon_fichier:
    for i in mon_fichier.readlines() :
        print(i)
qui donne dans la console :

Premier test d'"criture dans un fichier via Python

ligne2
Pourquoi y'a-t-il un saut d'une ligne entre les 2 lignes ? A cause des \n !

Changez votre code ainsi :

with open('fichier.txt', 'r' , ecoding='utf-8') as mon_fichier:
    for i in mon_fichier.readlines() :
        ligne=i.replace('\n','')
        print(ligne)
Cette fois il affiche bien :

Premier test d'écriture dans un fichier via Python
ligne2
Cette fois on a l'accentuation, et les retour de fin de ligne :

En résumé

Récapitulons le code complet lecture et écriture :

with open('fichier.txt', 'w' , encoding='utf-8') as mon_fichier:
    mon_fichier.write("Premier test d'écriture dans un fichier via Python\n")
    mon_fichier.write("ligne2\n")
with open('fichier.txt', 'r' , encoding='utf-8') as mon_fichier:
    for i in mon_fichier.readlines() :
        ligne=i.replace('\n','')
        print(ligne)
  • On peut ouvrir un fichier en utilisant la fonction open prenant en paramètre le chemin vers le fichier et le mode d'ouverture, il est bon d'ajouter la norme d'encodage avec encoding='utf-8'.
    1. On peut lire dans un fichier en utilisant la méthode read.
    2. On peut écrire dans un fichier en utilisant la méthodewrite.
    3. Un fichier doit être refermé après usage en utilisant la méthodeclose.
    On peut (et c'est préférable) utilise la méthode with (il faut aussi préciser le chemin, le mode et l'encodage)
    • Dans le bloc with on effectue les opération (read ou write, mais aussi tout ce qu'on voudra)
    • Quand on sort du bloc with (on enlève l'indentation) python referme le fichier.
    • On peut lire ligne par ligne dans une boucle for (cela est aussi possible avec open mais moins lisible et moins fiable)