Apprenez à programmer en Python
Last updated on Monday, September 8, 2014
  • 4 semaines
  • Facile

Free online content available in this course.

Paperback available in this course

eBook available in this course.

Certificate of achievement available at the end this course

Got it!

Les fichiers

Poursuivons notre tour d'horizon des principaux objets. Nous allons voir dans ce chapitre les fichiers, comment les ouvrir, les lire, écrire dedans.

Nous finirons ce chapitre en voyant comment sauvegarder nos objets dans des fichiers, afin de les utiliser d'une session à l'autre de notre programme.

Avant de commencer

Nous allons beaucoup travailler sur des répertoires et des fichiers, autrement dit sur votre disque. 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.

Changer le répertoire de travail courant

Si vous souhaitez travailler dans l'interpréteur Python, et je vous y encourage, vous devrez changer le répertoire de travail courant. En effet, au lancement de l'interpréteur, le répertoire de travail courant est celui dans lequel se trouve l'exécutable de l'interpréteur. Sous Windows, c'est C:\Python3X, le X étant différent en fonction de votre version de Python. Dans tous les cas, je vous invite à changer de répertoire de travail courant. Pour cela, vous devez utiliser une fonction du module os, qui s'appelle chdir(Change Directory).

>>> import os
>>> os.chdir("C:/tests python")
>>>

Pour que cette instruction fonctionne, le répertoire doit exister. Modifiez la chaîne passée en paramètre de os.chdir en fonction du dossier dans lequel vous souhaitez vous déplacer.

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.

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 dossier test, lui-même présent sur le disque C:, le chemin absolu menant à notre fichier sera C:\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 dossier C:\test et que l'on souhaite accéder au fichier fic.txt contenu dans ce même dossier, le chemin relatif menant à ce fichier sera tout simplement fic.txt.

Maintenant, si on se trouve dans C:, 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 dossier test que tout se passe. Nous avons deux sous-répertoires nommés rep1 et rep2. Dans rep1, nous avons un seul fichier : fic1.txt. Dans rep2, nous avons deux fichiers : fic2.txt et fic3.txt.

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

Résumé

Les chemins absolus et relatifs sont donc deux moyens de décrire le chemin menant à des fichiers ou répertoires. Mais, si le résultat est le même, le moyen utilisé n'est pas identique : quand on utilise un chemin absolu, on décrit l'intégralité du chemin menant au fichier, peu importe l'endroit où on se trouve. Un chemin absolu permet d'accéder à un endroit dans le disque quel que soit le répertoire de travail courant. L'inconvénient de cette méthode, c'est qu'on doit préalablement savoir où se trouvent, sur le disque, les fichiers dont on a besoin.

Le chemin relatif décrit la succession de répertoires à parcourir en prenant comme point d'origine non pas la racine, ou le périphérique sur lequel est stockée la cible, mais le répertoire dans lequel on se trouve. Cela présente certains avantages quand on code un projet, on n'est pas obligé de savoir où le projet est stocké pour construire plusieurs répertoires. Mais ce n'est pas forcément la meilleure solution en toutes circonstances.

Comme je l'ai dit, quand on lance l'interpréteur Python, on a bel et bien un répertoire de travail courant. Vous pouvez l'afficher grâce à la fonction os.getcwd() (CWD = « Current Working Directory »).

Cela devrait donc vous suffire. Pour les démonstrations qui vont suivre, placez-vous, à l'aide de os.chdir, dans un répertoire de test créé pour l'occasion.

Lecture et écriture dans un fichier

Nous allons commencer à lire avant d'écrire dans un fichier. Pour l'exemple donc, je vous invite à créer un fichier dans le répertoire de travail courant que vous avez choisi. Je suis en manque flagrant d'inspiration, je vais l'appeler fichier.txt et je vais écrire dedans, à l'aide d'un éditeur sans mise en forme (tel que le bloc-notes Windows) : « C'est le contenu du fichier. Spectaculaire non ? »

Ouverture du fichier

D'abord, il nous faut ouvrir le fichier avec Python. On utilise pour ce faire la fonction open, 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éé.

On peut ajouter à tous ces modes le signe b pour ouvrir le fichier en mode binaire. Nous en verrons plus loin l'utilité, c'est un mode un peu particulier.

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

>>> mon_fichier = open("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.

La fonction open crée donc un fichier. Elle renvoie un objet de la classe TextIoWrapper. Par la suite, nous allons utiliser des méthodes de 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 type file après tout. En fait, open permet d'ouvrir un fichier, mais TextIoWrapper est 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 est close :

>>> mon_fichier.close()
>>>

Lire l'intégralité du fichier

Pour ce faire, on utilise la méthode read de la classe TextIoWrapper. 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éthode read renvoie 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 variable contenu les signes \n traduisant un saut de ligne.

Maintenant que vous avez une chaîne, vous pouvez naturellement tout faire : la convertir, tout entière ou en partie, si c'est nécessaire, split la chaîne pour parcourir chaque ligne et les traiter… bref, tout est possible.

Écriture dans un fichier

Bien entendu, il nous faut ouvrir le fichier avant tout. Vous pouvez utiliser le mode w ou le mode a. 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.

>>> 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.close()
>>>

Vous pouvez vérifier que votre fichier contient bien le texte qu'on y a écrit.

Écrire d'autres types de données

La méthode write n'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.

Le module os contient beaucoup de fonctions intéressantes pour créer et supprimer des fichiers et des répertoires. Je vous laisse regarder l'aide si vous êtes intéressé.

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 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 appelle open qui va renvoyer un objet TextIOWrapper (notre fichier).

  • Le mot-clé as que 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 signifie simplement que, si une exception se produit, le fichier sera tout de même fermé à la fin du bloc.

Le mot-clé with permet 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 appeler mon_fichier.closed pour vérifier que le fichier est refermé. Si le fichier est fermé, mon_fichier.closed vaudra True.

Il est inutile, par conséquent, de fermer le fichier à la fin du bloc with. 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.

Allez ! Direction le module pickle, dans lequel nous allons apprendre à sauvegarder nos objets dans des fichiers.

Enregistrer des objets dans des fichiers

Dans beaucoup de langages de haut niveau, on peut enregistrer ses objets dans un fichier. Python ne fait pas exception. Grâce au module pickle que nous allons découvrir, on peut enregistrer n'importe quel objet et le récupérer par la suite, au prochain lancement du programme, par exemple. En outre, le fichier résultant pourra être lu depuis n'importe quel système d'exploitation (à condition, naturellement, que celui-ci prenne en charge Python).

Enregistrer un objet dans un fichier

Il nous faut naturellement d'abord importer le module pickle.

>>> import pickle
>>>

On va ensuite utiliser deux classes incluses dans ce module : la classe Pickler et la classe Unpickler.

C'est la première qui nous intéresse dans cette section.

Pour créer notre objet Pickler, nous allons l'appeler en passant en paramètre le fichier dans lequel nous allons enregistrer notre objet.

>>> with open('donnees', 'wb') as fichier:
...     mon_pickler = pickle.Pickler(fichier)
...     # enregistrement ...
... 
>>>

Quand nous allons enregistrer nos objets, ce sera dans le fichier donnees. Je ne lui ai pas donné d'extension, vous pouvez le faire. Mais évitez de préciser une extension qui est utilisée par un programme.

Notez le mode d'ouverture : on ouvre le fichier donnees en mode d'écriture binaire. Il suffit de rajouter, derrière la lettre symbolisant le mode, la lettre b pour indiquer un mode binaire.

Le fichier que Python va écrire ne sera pas très lisible si vous essayez de l'ouvrir, mais ce n'est pas le but.

Bon. Maintenant que notre pickler est créé, nous allons enregistrer un ou plusieurs objets dans notre fichier. Là, c'est à vous de voir comment vous voulez vous organiser, cela dépend aussi beaucoup du projet. Moi, j'ai pris l'habitude de n'enregistrer qu'un objet par fichier, mais il n'y a aucune obligation.

On utilise la méthode dump du pickler pour enregistrer l'objet. Son emploi est des plus simples :

>>> score = {
...   "joueur 1":    5,
...   "joueur 2":   35,
...   "joueur 3":   20,
...   "joueur 4":    2,
>>> }
>>> with open('donnees', 'wb') as fichier:
...     mon_pickler = pickle.Pickler(fichier)
...     mon_pickler.dump(score)
... 
>>>

Après l'exécution de ce code, vous avez dans votre dossier de test un fichier donnees qui contient… eh bien, notre dictionnaire contenant les scores de nos quatre joueurs. Si vous voulez enregistrer plusieurs objets, appelez de nouveau la méthode dump avec les objets à enregistrer. Ils seront ajoutés dans le fichier dans l'ordre où vous les enregistrez.

Récupérer nos objets enregistrés

Nous allons utiliser une autre classe définie dans notre module pickle. Cette fois, assez logiquement, c'est la classe Unpickler.

Commençons par créer notre objet. À sa création, on lui passe le fichier dans lequel on va lire les objets. Puisqu'on va lire, on change de mode, on repasse en mode r, et même rb puisque le fichier est binaire.

>>> with open('donnees', 'rb') as fichier:
...     mon_depickler = pickle.Unpickler(fichier)
...     # Lecture des objets contenus dans le fichier...
... 
>>>

Pour lire l'objet dans notre fichier, il faut appeler la méthode load de notre depickler. Elle renvoie le premier objet qui a été lu (s'il y en a plusieurs, il faut l'appeler plusieurs fois).

>>> with open('donnees', 'rb') as fichier:
...     mon_depickler = pickle.Unpickler(fichier)
...     score_recupere = mon_depickler.load()
... 
>>>

Et après cet appel, si le fichier a pu être lu, dans votre variable score_recupere, vous récupérez votre dictionnaire contenant les scores. Là, c'est peut-être peu spectaculaire mais, quand vous utilisez ce module pour sauvegarder des objets devant être conservés alors que votre programme n'est pas lancé, c'est franchement très pratique.

En résumé

  • On peut ouvrir un fichier en utilisant la fonction open prenant en paramètre le chemin vers le fichier et le mode d'ouverture.

  • On peut lire dans un fichier en utilisant la méthode read.

  • On peut écrire dans un fichier en utilisant la méthode write.

  • Un fichier doit être refermé après usage en utilisant la méthode close.

  • Le module pickle est utilisé pour enregistrer des objets Python dans des fichiers et les recharger ensuite.

Example of certificate of achievement
Example of certificate of achievement