Fichiers

On appelera fichier toute collection de données (textuelles ou binaires) enregistrée sur un support physique (un disque dur, une clé usb, etc). Un fichier peut être accessible en lecture seule, ou en lecture/écriture. Pour pouvoir être consulté et/ou modifié, il doit être ouvert d’abord, puis fermé ensuite (mais Python se charge souvent de fermer le fichier lui-même quand tout est terminé).

Python propose la classe file pour modéliser la notion de fichier, et pour faciliter les interactions. Tout dépend beaucoup du système d’exploitation (Windows, Linux, Mac OSX, etc) mais la classe file offre des méthodes qui permettent de masquer les différences.

Dans tous les cas, un fichier possède un nom et réside (ou est créé) dans un dossier. Pour accéder au fichier, on a besoin de son nom et du chemin d’accès à son dossier.

Par défaut, il s’agit du “dossier courant”, c’est-à-dire celui où réside le script en cours d’exécution (ou alors le dernier script utilisé, ou celui de l’application IDLE si on travaille en mode interactif).

Dans toute la suite de cette section, on suppose qu’on se place uniquement dans le “dossier courant”. Les fichiers seront donc désignés par leur nom, simplement, sans indication d’un chemin d’accès.

Mais si on veut un contrôle précis sur les dossiers, on importera le module os (pour “operating system”) qui fournit quelques fonctions utiles : os.chdir("chemin") désigne un nouveau dossier de travail, os.getcwd() renvoie le dossier de travail actuel (“get current directory”).

On ne confondra pas les objets de type file tels qu’ils sont créés et manipulés par Python (voir plus loin) avec la concrétisation “physique” de ces fichiers sur le disque. En fait, les objets file sont des abstractions permettant de désigner commodément ces fichiers “physiques”.

On se contentera ici d’indiquer les principales fonctions ayant trait aux fichiers :

  • Ouverture et fermeture :
    myfile = open(str,mode/type,encoding) et myfile.close()
    Ici myfile est l’identificateur associé à l’objet abstrait de type file, lui-même associé au fichier physique dont le nom est la chaîne str, en spécifiant le mode et le type d’accès.
    Par défaut, l’accès est 'rt', c’est-à-dire 'r' (lecture) et 't' (fichier texte).
    Les modes d’accès sont 'r' (reading : lecture seule), 'w' (writing : avec effaçage si le fichier s’il existe), 'x' (création exclusivement, avec erreur si le fichier existe), 'a' (append : écriture à la fin du fichier s’il existe).
    Il convient d’indiquer l’encodage quant on ouvre le fichier (par exemple en écrivant encoding = 'utf-8' si le fichier texte est en Unicode, ou encoding = 'Latin-1', etc).
    Les deux principaux types d’accès sont 'b' (binaire), 't' (texte).
  • Lecture d’un fichier texte :
    myfile.read(n) (n caractères, et par défaut la totalité du fichier) : le résultat est une chaîne de caractères.
    myfile.readline() renvoie une ligne de texte, terminée par le caractère \n de fin de ligne.
    myfile.readlines() renvoie la liste de toutes les lignes de texte.
  • Écriture dans un fichier texte :
    myfile.write(chaine) écrit une chaîne de caractères dans un fichier texte.
  • Lecture/écriture dans un fichier binaire :
    Le module pickle permet d’écrire/lire des données de type quelconque (on n’est donc plus obligé de préciser soit un nombre de caractères, soit une chaîne). Le fichier doit être ouvert en binaire, en écriture ('wb') ou en lecture ('rb').
    Après import pickle , la syntaxe est pickle.dump(obj,myfile) (enregistrer obj) et obj=pickle.load(myfile)
  • Lecture séquentielle d’un fichier texte :
    La syntaxe for ligne in myfile permet de lire séquentiellement les différentes lignes d’un fichier texte, celui-ci étant donc traité comme un itérateur (c’est la boucle for qui se charge de tout, et en particulier du rattrapage de l’exception quand la lecture du fichier est terminée). Cette syntaxe est supérieure à myfile.readlines(), qui charge la totalité du fichier en mémoire sous la forme d’une liste de chaînes.

Nous allons traiter un petit exemple, à partir du texte du poème “Nuit Rhénane” de Guillaume Apollinaire.

On crée un fichier texte, en écriture, encodé en utf-8, de nom “nuit-rhenane.txt” sur le disque. Dans la suite, on doit utiliser l’identificateur poeme, et non pas “nuit-rhenane.txt”. C’est en effet l’objet poeme qui possède les méthodes qu’on va utiliser. On voit que poeme est en fait un objet de type TextIOWrapper (mais c’est sans grande importance) :

On écrit maintenant deux lignes dans le fichier. On les termine par le caractère de fin de ligne \n.

À chaque fois, la fonction write de l’objet poeme renvoie le nombre de caractères enregistrés (y compris \n) :

On peut bien sûr écrire plusieurs lignes de textes consécutivement, à condition de penser au séparateur \n. Attention, ici le caractère \ qui termine la première ligne (juste après \n) ne fait pas partie de la chaîne écrite : c’est une commodité de l’éditeur Python pour indiquer un passage à la ligne non significatif (simplement parce que le texte entré ici est trop long pour tenir sur une seule ligne à l’écran) :

Le poème est incomplet, et voici les vers manquants, sous forme d’une liste (avec la place prévue pour les lignes vides). Remarque : dans la saisie d’une liste aussi longue, l’éditeur de Python ne nécessite pas d’utiliser le caractère \, et il attend sagement que la liste soit terminée par le caractère ].

Le fichier ayant été fermé (mais incomplet), on décide de le réouvrir, mais attention, en mode append (sinon on effacerait ce qui vient d’être enregistré !). À l’aide d’une boucle for (en itérant sur les éléments v de liste), on écrit chacun des vers manquants au poème (attention à bien rajouter les caractères \n de fin de ligne) :

Ouvrons à nouveau le fichier poeme, mais en mode lecture. On lit les deux premières lignes (avec deux appels à poem.readline()). On voit que les caractères de terminaison \n figurent à la fin de chaque ligne lue :

NB : si on est arrivé à la fin du fichier, readline renvoie une chaîne vide (donc ne lève pas une exception).

Un appel à readlines() (attention au “ s ”) renvoie alors le reste du fichier, sous forme d’une liste de chaînes, avec les \n de terminaison (on n’a pas tout reproduit ici, même si c’est beau). Puis on referme le fichier (c’est plus prudent).

On l’ouvre ensuite (en mode par défaut : “text/read”) puis on lit et affiche le poème par l’intermédiaire d’une boucle for.

Bien penser à l’option end="" sans laquelle les caractères de fin de ligne (déjà présents dans le fichier) seraient doublés par le passage à la ligne inhérent à la fonction print :

Remarque importante :

  • quand on ouvre un fichier-texte file en lecture, l’expression ch =''.join(file) renvoie dans ch une chaîne obtenue
    par concaténation de toutes les chaînes du fichier (impressionnant !).
  • L’expression ch.split(sep='\n') renvoie alors la liste des chaînes obtenues par séparation au niveau des \n.

Voici maintenant un petit exemple avec le module pickle.

On ouvre un fichier binaire en écriture, et on y inscrit les carrés des entiers de 1 à 9.

On l’ouvre ensuite en lecture, comme s’il s’agissait d’un fichier texte. La fonction read conduit bien sûr à une erreur (le premier caractère n’est pas reconnu comme un code ascii, mais ce serait pareil si on avait précisé l’encodage utf-8).

Tout va mieux en ouvrant le fichier en lecture binaire. On récupère les neuf données binaires écrites précédemment :

Retour à l’accueil du cours Python/Numpy

Sommaire du chapitre 6

  1. Dictionnaires
  2. Ensembles
  3. Itérateurs
  4. Fonctions utiles sur les itérateurs
  5. Générateurs (instruction yield)
  6. Fichiers