Lire et écrire dans un fichier.

Créer un fichier et écrire dans ce fichier

Exemple.

On écrit la table du 6 à l'écran, puis dans un fichier.


# affichage de la table du 6
print ("Table du 6 :")    
for j in range(1,11) :
    print('6 x', j, '=', 6*j)


# création et ouverture d'un fichier texte 
# que l'on nomme table_du_6.txt
# et accessible via l'objet fich_cible

with open( "table_du_6.txt", "w", encoding="utf-8") as fich_cible :
    # Inscrire la table du 6 dans le fichier
    print ("Table du 6 :", file=fich_cible)
    for j in range(1,11) :
        print('6 x', j, '=', 6*j, file=fich_cible)
        
# fermeture automatique du fichier
# en sortant du bloc (indenté) définissant de traitement de ce fichier 

Quelques remarques

  • Le second argument de open ('w') définit un mode d'ouverture. Celui qui est présenté crée le fichier s'il n'existe pas et l'écrase s'il existe. Il y en a d'autre qui seront présentés plus loin sur cette page.
  • Le troisième argument de open sépcifie l'encodage des caractères, les modes d'ouverture courant anipulant les fichier comme des chaines de caracctère. Cemmen en html, l'ommettre peut-être problématique, et il n'y a pas de raison d'en choisir un autre.
  • Ici le fichier est créé dans le même dossier que le fichier .py. On peut tout-à-fait utiliser un chemin relatif à partir de cet emplacement, pour mettre le fichier ailleurs. Pour utiliser un chemin absolu, il faut être sûr qu'il mène quelque part ! Pour les plus curieux : on peut pour ça utiliser le module os, et en particulier sa fonction getcwd.
  • La fonction print a le même comportement dans un fichier qu'en sortie console : elle produit des chaines de caractères, sépare ses arguments par un espace, et va à la ligne à la fin. On peut modifier ces comportements avec les arguments sep et end. Pour plus d'information, on peut consulter la page d'aide de print dans la console python: help(print).

Lire le contenu d'un fichier

Fichier entier


# place le contenu du fichier "table_du_6.txt" dans la variable contenu
with open("table_du_6.txt", "r", encoding="utf-8") as fich_source:
    contenu = fich_source.read()
# à la fin du bloc indenté, le fichier est fermé
# on peut en lire le contenu dans la variable contenu

#ici, on l'affiche à l'écran, par exemple
print( contenu)
	  

Le mode d'ouverture "r" ouvre le fichier en lecture seule.

La méthode read() renvoie tout le contenu du fichier sous la forme d'une chaine de caractères.

Parcours ligne par ligne

Le programme ci-dessous affiche le contenu du fichier "table_du_6.txt" en ajoutant des numéros de ligne


with open("table_du_6.txt", "r", encoding="utf-8") as fich_source:
    k = 1 # compteur des lignes
    for ligne in fich_source:
        print (k, ligne)
        k += 1
	  

Ici, des lignes vides sont affichées parce que print va a la ligne, et que la variable ligne contient elle aussi un saut de ligne à la fin. On peut corriger celà de deux façons :


with open("table_du_6.txt", "r", encoding="utf-8") as fich_source:
    k = 1 # compteur des lignes
    for ligne in fich_source:
        print (k, ligne, end='')  # on empêche print d'aller à la ligne
        k += 1
	  

with open("table_du_6.txt", "r", encoding="utf-8") as fich_source:
    k = 1 # compteur des lignes
    for ligne in fich_source:
        ligne.rstrip()     # retire les espaces et sauts de ligne à la fin de la chaine
        print (k, ligne)
        k += 1
	  

Liste des lignes


#on obtient la liste des lignes
with open("table_du_6.txt", "r", encoding="utf-8") as fich_source:
    liste_des_lignes = fich_source.readlines()

#on en affiche une sur deux
for k in range(len(liste_des_lignes)):
    if k%2==0:
        print (liste_des_lignes[k])
	  

Il existe aussi la méthode .readline() (sans 's') qui permet de ne lire qu'une seule ligne du fichier, et qui permet de le lire ligne par ligne sans être nécessairement dans une boucle for qui parcourt l'ensemble des lignes.

Écrire à la fin d'un fichier

On veut inscrire les tables du 6 et du 7 dans le même fichier.

On commence par la table du 6 comme précédemment


with open( "tables.txt", "w", encoding="utf-8") as fich_cible :
    # Inscrire la table du 6 dans le fichier
    print ("Table du 6 :", file=fich_cible)
    for j in range(1,11) :
        print('6 x', j, '=', 6*j, file=fich_cible)
          

Ce code doit être suivi de


with open( "tables.txt", "a", encoding="utf-8") as fich_cible :
    # Inscrire la table du 7 dans le fichier
    print ("Table du 7 :", file=fich_cible)
    for j in range(1,11) :
        print('7 x', j, '=', 7*j, file=fich_cible)
          

En dehors du contenu, le seul changement dans la manipulation du fichier est le mode d'ouverture fixé à "a" (pour 'append') qui ouvre le fichier en écriture de façon à ajouter le contenu à la fin.

Si le fichier n'exite pas, le mode "a" le crée avant de l'ouvrir, comme "w".

JSON

En projet, pour sauvegarder dans des fichiers le tableau des scores, la positon d'un plateau de jeu ou d'autres données complexes, il sera certainement plus commmode de pouvoir sauvegarder des variables python avec leurs types plutôt que simplement des chaines de caractères. Sans aller jusqu'à concevoir son propre format de fichier, ceci peut-être effectué en utilisant une transcription automatique et standard des variables en chaines de caractères avec le module json.

dumps, loads

json.dumps transforme une variable python en chaine de caractère, de façon à ce que json.loads puisse l'interpréter et retrouver la variable originale, avec sa valeur et son type.


import json
	      
variable  = [[ 1, 2, 3], [ 4, 5, 6], ['x', 'y', 'z']]

# la sauvegarde
with open( "sauvegarde.json", "w", encoding="utf-8") as fich_cible :
    print ( json.dumps(variable), file=fich_cible)

# la lecture
with open( "sauvegarde.json", "r", encoding="utf-8") as fich_source :
    variable2 = json.loads( fich_source.read())

# a-t-on bien retrouvé les données ?
print (variable == variable2)
	  

Dictionnaires

Si on veut sauvegarder plusieurs objets python dans le même fichier, y écrire plusieurs chaines json ne résout pas le problème de départ : les efforts pour les distinguer reviennent à élaborer son propre format de fichier. Il est nettement plus commode de les regrouper dans un seul obet python. Il est naturel et tout à fait raisonnable de le faire dans une liste, mais les dictionnaires offrent un moyen encore plus lisible.

Dans cet exemple on veut sauvegarder le nom du joueur, son score et le plateau de jeu.


import json
	      
nom_joueur = "Toto"
score = 31415927
plateau = [ [ 'mur', 'mur', 'sortie', 'mur'] , [ 'mur', 'joueur', 'vide', 'mur'], ['mur', 'mur', 'mur', 'mur']]

# on constitue le dictionnaire
sauvegarde = {} # on initialise la variable avec un dictionnaire vide
sauvegarde['nom'] = nom_joueur
sauvegarde['score'] = score
sauvegarde['plateau'] = plateau

# la sauvegarde
with open( "sauvegarde.json", "w", encoding="utf-8") as fich_cible :
    print ( json.dumps(sauvegarde), file=fich_cible)

# la lecture
with open( "sauvegarde.json", "r", encoding="utf-8") as fich_source :
    chargement = json.loads( fich_source.read())

# a-t-on bien retrouvé les données ?
print (nom_joueur == chargement['nom'])
print (score == chargement['score'])
print (plateau == chargement['plateau'])
	  

Opérations complexes

open + close

Pour effectuer des opérations plus complexes, éventuellement sur plusieurs fichiers, ou éviter de multiplier les niveaux d'indentation, on peut séparer les instructions d'ouverture et de fermeture en se passant d'un bloc with. Ainsi l'inscription de la table du 6 dans le fichier "table_du_6.txt" peut être réalisée de façon équivalente par ce code :


fich_cible = open( "table_du_6.txt", "w", encoding="utf-8")
print ("Table du 6 :", file=fich_cible)
for j in range(1,11) :
    print('6 x', j, '=', 6*j, file=fich_cible)
fich_cible.close()
          

Modes d'ouverture

Si on décide d'effectuer à la fois des opérations de lecture et d'écriture sur le fichier, on peut ajouter "+" au mode d'ouverture choisi. Pour résumer :

  • Le mode "w" permet d'écrire dans le fichier, et en efface le contenu précédent.
  • Le mode "r" permet de lire le fichier (depuis le début).
  • Le mode "a" permet d'écrire à la fin du fichier.
  • Le mode "w+" efface le fichier, mais permet d'écrire et lire dedans ensuite.
  • Le mode "r+" permet de lire et d'écrire dans le fichier, en étant initialement positionné au début du fichier.
  • Le mode "a+" permet de lire et d'écrire dans le fichier, en étant initialmeent positionné à la fin du fichier.

Les autres modes proposés sont décrits dans l'aide de la fonction open.

write, seek, read(n)

La méthode .write permet d'écrire dans le fichier. Elle prend en argumen une chaine de caractères (ou de bytes, dépend du mode d'ouverture du fichier) et l'écrit dans le fichier. Contrairement à print, elle n'opère pas de mise en forme.


# ériture de la table de 6 avec write
with open( "table_du_6.txt", "w", encoding="utf-8") as fich_cible :
    #Inscrire la table du 6 dans le fichier
    fich_cible.write("Table du 6 :\n") # on doit ajouter le saut de ligne '\n'
    for j in range(1,11) :
        fich_cible.write("6 x {} = {}\n".format(j,6*j)) # il faut convertir 
                          # explicitement en str pour les sortie complexes

En mettant un entier en argument de .read(), on peut lire un nombre donné de caractères plutôt que l'intégralité du fichier.


with open( "table_du_6.txt", "r", encoding="utf-8") as fich_source :
    #lire les 3 premier caractères    
    debut = fich_source.read(3)
    #puis les 5 suivants
    suite = fich_source.read(5)
	  

Pour finir, .seek() permet de changer sa position dans le fichier, suivant plusieurs modes de repérage.


with open( "table_du_6.txt", "r+", encoding="utf-8") as fich_source :
    #lire 3 caractères à partir de la position 10
    fich_source.seek(10)
    morceau = fich_source.read(3)
	  

Ces opérations seront étudiées, avec l'aide des professeurs, en cas de nécessité pour le projet ou de curiosité personnelle.