Accueil » Leçon 6 - Les fichiers

Leçon 6 - Les fichiers

Objectifs de la leçon :

Cette leçon est centrée sur la manipulation des fichiers :

  • Lecture de fichiers
  • Écriture de fichiers
  • Manipulation (copie / suppression / renommage / etc.) de fichiers

Pour tester les codes présentés dans cette leçon, il vous faudra obligatoirement travailler sur votre ordinateur. Du fait que nous allons travailler sur des fichiers, il n'est pas possible d'exécuter les scripts sur le site.

Pré-requis :

La leçon 1 : afficher, saisir, les variables, les calculs.

La leçon 2 : les structures conditionnelles.

La leçon 3 : les fonctions.

La leçon 4 : les boucles.

La leçon 5 : les listes.

Des exemples pour démarrer

Pour travailler avec le contenu des fichiers (lire ou écrire), il faut « ouvrir » ces fichiers avec la fonction « open() ». Cette fonction prend obligatoirement deux paramètres : le fichier (avec son chemin relatif ou absolu), et le mode d'ouverture. C'est le « mode d'ouverture » qui défini si on va simplement lire le contenu du fichier, ou si on va écrire dedans.

Ouvrir un fichier en lecture

Pour notre exemple, créez d'abord un fichier « liste-courses.txt » avec pour contenu, par exemple :

salade
tomates
oignons
Ensuite, dans le même dossier, créez un fichier Python « lecture.py » :

#!/usr/bin/env python3

# ouverture en lecture
fichier = open('liste-courses.txt', 'r')

# on parcours le contenu du fichier ligne par ligne
for ligne in fichier:
    print(ligne)

# il ne faut pas oublier de fermer le fichier
fichier.close()
Pour être en mode « lecture », on a utilisé le mode « r » (pour « read »). On a donc ouvert en lecture le fichier « liste-courses.txt » qui se trouve dans le même répertoire que notre script.

Ouvrir un fichier en écriture

Maintenant avec le script suivant, qu'on peut appeler « ecriture.py », on va écrire dans notre fichier.

#!/usr/bin/env python3

# ouverture en écriture
fichier = open('liste-courses.txt', 'w')

# on écrit des éléments dans notre fichier
fichier.write('bananes\n')
fichier.write('pommes\n')
fichier.write('fraises\n')

fichier.close()
Vous l'avez remarqué, ici on a utilisé le mode « w » (pour « write »).

Si vous avez regardé le contenu du fichier « liste-courses.txt », vous avez aussi remarqué qu'il a été écrasé par ce que vous venez d'y écrire.

En effet, le mode « write » écrase le fichier s'il existe déjà, et le créé s'il n'existe pas.

Ouvrir un fichier en ajout

Si on veut écrire à la suite du fichier, il faut utiliser le mode « a » (pour « append »).

#!/usr/bin/env python3

# ouverture en écriture (à la suite)
fichier = open('liste-courses.txt', 'a')

fichier.write('salade\n')
fichier.write('tomates\n')
fichier.write('oignons\n')

fichier.close()
Vous pouvez vérifier, cette fois-ci les éléments se sont ajoutés à la fin du fichier.

Dans le cas où le fichier n'existait pas initialement, de même qu'en mode « w », il aurait été créé.

L'ESSENTIEL AVEC DES EXEMPLES DE BASE

Ouverture en lecture

Pour ouvrir un fichier en lecture, il faut utiliser la fonction `open()` qui prend en arguments :

  • le nom du fichier (chemin absolu ou relatif) ;
  • et le mode d'ouverture `r` (read).

Le fichier ouvert étant verrouillé, il ne faut pas oublier de le fermer avec la méthode `close()`.

# ouverture
fichier = open('liste-courses.txt', 'r')

# lecture
contenu = fichier.read()
print(contenu)

# fermeture
fichier.close()
Lors du parcours du fichier, si une erreur se produit et que le fichier n'est pas fermé, il devient inutilisable dans la suite du programme. Dans certains cas, il est donc préférable d'utiliser la fonction `open()` avec le mot clé `with` qui s'occupera de fermer le fichier en cas d'exception. Dans ce cas il n'est plus nécessaire de fermer explicitement le fichier.

with open('liste-courses.txt', 'r') as fichier:
    contenu = fichier.read()
    print(contenu)

Parcourir un fichier

Après avoir ouvert un fichier, il existe différentes méthodes pour le parcourir :

  • la méthode `read()` retourne tout le contenu du fichier dans une variable de type `string`
contenu = fichier.read()
  • la méthode `readline()` retourne la première ligne du fichier lors de son premier appel, la seconde ligne à son second appel, la troisième, etc.
ligne1 = fichier.readline()  # ligne 1
ligne2 = fichier.readline()  # ligne 2
  • la méthode `readlines()` retourne toutes les lignes du fichier dans une variable de type `list`
liste_lignes = fichier.readlines()
  • la boucle `for`, c'est la plus efficace pour parcourir de très gros fichiers, elle s'utilise directement sur l'objet
for ligne in fichier:
    […]

Ouverture en écriture

Pour ouvrir en écriture, il faut utiliser le mode `w` (write). Si le fichier n'existe pas, il sera créé. Par contre, s'il existe déjà, il sera écrasé.

# ouverture
fichier = open('liste-courses.txt', 'w')

# écrire
fichier.write('papier toilette')

# fermeture
fichier.close()
La même chose avec le mot-clé `with` :

with open('liste-courses.txt', 'w') as fichier:
    fichier.write('papier toilette')

Ouverture en ajout

Pour ouvrir en ajout, il faut utiliser le mode `a` (append). Si le fichier n'existe pas, il sera créé. S'il existe déjà, les écritures s'ajouteront à la fin du fichier existant.

# ouverture
fichier = open('liste-courses.txt', 'a')

# écrire
fichier.write('dentifrice')

# fermeture
fichier.close()
La même chose avec le mot-clé `with` :

with open('liste-courses.txt', 'a') as fichier:
    fichier.write('dentifrice')

Opérations sur les fichiers et dossiers

  • Se placer dans un dossier
import os

os.chdir('/chemin/dossier/')
  • Récupérer le répertoire de travail
import os

chemin = os.getcwd()
  • Lister le contenu d'un dossier
import os

liste = os.listdir('/chemin/dossier/')
  • Renommer un fichier ou un dossier
import os

os.rename('ancien_nom.txt', 'nouveau_nom.txt')
  • Supprimer un fichier
import os

os.remove('fichier.txt')
  • Créer un dossier
import os

os.mkdir('/chemin/dossier_vide/')
  • Supprimer un dossier vide
import os

os.rmdir('/chemin/dossier_vide/')
  • Supprimer un dossier et son contenu
import shutil

shutil.rmtree('/chemin/dossier/')

 Tests sur les fichiers et dossiers

  • Vérifier si le fichier ou dossier existe
import os

if os.path.exists('/chemin/fichier.txt'):
    print('Le fichier existe.')
  • Vérifier s'il s'agit d'un fichier
import os

if os.path.isfile('/chemin/fichier.txt'):
    print("L'élément est un fichier.")
  • Vérifier s'il s'agit d'un dossier
import os

if os.path.isdir('/chemin/dossier/'):
    print("L'élément est un dossier.")
  • Vérifier s'il s'agit d'un lien
import os

if os.path.islink('/chemin/symlink'):
    print("L'élément est un lien.")
  • Vérifier s'il s'agit d'un point de montage
import os

if os.path.ismount('/chemin/mount_point/'):
    print("L'élément est un point de montage.")
Dans certains cas, plutôt que de faire l'un des tests ci-dessus, il est recommandé d'utiliser un bloc `try: […] except:` pour l'ouverture de fichiers. Cela permet de s'assurer qu'entre le test (existence, fichier, etc.) et l'ouverture, le fichier n'a pas été modifié ou supprimé.
try:
    with open('schrodinger-file.txt', 'r') as fichier:
        contenu = fichier.readlines()
except IOError as erreur:
    print(erreur)


Quelques exemples plus poussés

Numérotation des lignes d'un fichier

Le script ci-dessous parcours un fichier donné et en affiche chaque lignes avec son numéro de ligne. Il est volontairement sur-commenté pour que vous compreniez chaque étape.

# import du module `os`
import os

# initialisation d'un compteur pour le numéro de ligne
i = 0

# demande de saisie du nom du fichier à traiter
nom_fichier = input('Saisir nom du fichier : ')

# si le fichier existe
if os.path.isfile(nom_fichier):
    # ouvrir le fichier
    fichier = open(nom_fichier, 'r')
# sinon
else:
    # afficher un message d'erreur
    print('Erreur : `' + nom_fichier + '` n\'existe pas ' +
          'ou n\'est pas un fichier.')
    # quitter le programme avec un code d'erreur
    exit(1)

# récupérer les lignes du fichier dans une liste
contenu = fichier.readlines()
# fermer le fichier
fichier.close()

# parcours de chaque élément de la liste de lignes
for ligne in contenu:
    # incrémentation du numéro de ligne
    i += 1
    # suppression du retour chariot en fin de ligne
    ligne = ligne.rstrip()
    # affichage du numéro et de la ligne
    print(str(i) + '. ' + ligne)

Optimisation du script

Ci-dessous on a repris le même script en optimisant certains aspects.

  • Sécurité : On a remplacé le test `isfile` par un bloc `try: […] except:`. De cette manière si l'élément saisit par l'utilisateur n'est pas un fichier, n'est pas lisible ou est supprimé entre temps, une exception est levée et capturée, plutôt que de faire planter le programme.
  • Sécurité : On a utilisé le mot clé `with` pour l'ouverture du fichier. De cette manière, si une erreur se produit lors du parcours du fichier, celui-ci est refermé automatiquement, contrairement à l'ouverture classique, pour laquelle il faut explicitement refermer le fichier avec la méthode `close()`. Sans ça, il serait impossible de réutiliser le fichier dans la suite programme.
  • Performance : L'utilisation du bloc `try: […] except:` permet d'éviter l'import du module `os`, et donc de limiter le nombre de lignes, ainsi que l'empreinte mémoire de notre script.
  • Performance : On a remplacé l'utilisation de la méthode `readlines()` par un parcours de l'objet avec la boucle `for` directement sur celui-ci (comme s'il s'agissait d'une liste). Sur de petits fichiers le gain est négligeable, mais pour de très gros fichier cette optimisation prend tout son sens.
# initialisation d'un compteur pour le numéro de ligne
i = 0

# demande de saisie du nom du fichier à traiter
nom_fichier_in = input('Saisir nom du fichier : ')

# « essayer » le bloc d'instructions
try:
    # ouvrir le fichier
    with open(nom_fichier_in, 'r') as fichier:
        # parcours de l'objet `fichier`
        for ligne in fichier:
            # incrémentation du numéro de ligne
            i += 1
            # suppression du retour chariot en fin de ligne
            ligne = ligne.rstrip()
            # affichage du numéro et de la ligne
            print(str(i) + '. ' + ligne)
# en cas d'erreur de type `IOError`, la récupérer dans la variable `erreur`
except IOError as erreur:
    # afficher l'erreur
    print(erreur)
    # quitter le programme avec un code d'erreur
    exit(1)
L'utilisation de certaines syntaxes et optimisations peuvent dépendre du contexte et du rôle que remplit votre programme. Dans notre exemple, les optimisations liées à la sécurité n'était peut-être pas nécessaires, surtout l'utilisation de `with` qui ne simplifie pas la structure du code. À vous dans votre écriture de code de juger de la pertinence de telle ou telle écriture.

Avec écriture

Encore une fois le même script, mais cette fois-ci au lieu d'afficher la sortie à l'écran, on l'écrit dans un fichier.

# initialisation d'un compteur pour le numéro de ligne
i = 0

# saisies de noms de fichiers
nom_fichier_in = input('Saisir nom du fichier source : ')
nom_fichier_out = input('Saisir nom du fichier de sortie : ')

# les fichiers doivent être différents
if nom_fichier_in == nom_fichier_out:
    print('Impossible d\'utiliser le même fichier en entrée et en sortie !')
    exit(1)

try:
    # ouvertures
    fichier_in = open(nom_fichier_in, 'r')
    fichier_out = open(nom_fichier_out, 'w')
    # parcours `fichier_in`
    for ligne in fichier_in:
        i += 1
        # écriture `fichier_out`
        fichier_out.write(str(i) + '. ' + ligne)
    # fermetures
    fichier_in.close()
    fichier_out.close()
except IOError as erreur:
    print(erreur)
    exit(1)

Des pièges à éviter

Ouvrir en écriture à l'intérieur d'une boucle

Exemple (de ce qu'il ne faut pas faire !) :

# ouvertures
fichier_in = open(nom_fichier_in, 'r')

# parcours `fichier_in`
for ligne in fichier_in:
    # écriture `fichier_out`
    fichier_out = open(nom_fichier_out, 'w')
    fichier_out.write(ligne)
    fichier_out.close()

# fermetures
fichier_in.close()
Ici, étant donne que `fichier_out` est ouvert en mode `write`, il est écrasé à chaque itération de la boucle. A la fin du script, il ne contiendra donc que la dernière ligne de `fichier_in`.

Bon à savoir

Explorer les possibilités

La fonction `open()` renvoie un objet de la classe `TextIOWrapper`, qui elle-même hérite de `TextIOBase`. Ce sont les méthodes de ces classe que nous utilisons pour interagir avec le fichier. Il en existe d'autre que celles que nous avons vu, vous pouvez les retrouver dans la documentation Python3 en lien sur les classes.

Sauvegarder des objets dans des fichiers

Avec le module `pickle` on peut écrire/sauvegarder des objets dans des fichiers. De cette manière il devient possible de les récupérer au prochaine lancement du programme.

Le quiz

Exercice à choix multiple : Ouverture
Quelle est la fonction qui permet d'ouvrir un fichier ?
Correct !

Exercice à choix multiple : Arguments
Quels sont le ou les arguments obligatoires à la fonction `open()` ?
Correct ! En effet, le mode d'ouverture n'est pas obligatoire, par défaut le fichier sera ouvert en mode `read`.

Exercice à choix multiple : Mode ouverture 1
Avec l'ouverture ci-dessous, dans quel mode est ouvert le fichier ?
open('fichier.txt', 'a')
Correct !

Exercice à choix multiple : Mode ouverture 2
Avec l'ouverture ci-dessous, dans quel mode est ouvert le fichier ?
open('fichier.txt', 'w')
Correct !

Exercice à choix multiple : Mode ouverture 3
Avec l'ouverture ci-dessous, dans quel mode est ouvert le fichier ?
open('fichier.txt', 'r')
Correct !

Exercice à choix multiple : Mode ouverture 4
Avec l'ouverture ci-dessous, dans quel mode est ouvert le fichier ?
open('fichier.txt')
Correct ! Si le mode n'est pas spécifié, par défaut le fichier est ouvert en lecture.

Exercice à choix multiple : Exception
Quel est le type d'erreur levé si `fichier.txt` n'existe pas ?
try:
fichier = open('fichier.txt')
Except ???:
exit(1)
Correct ! Essayez par exemple de code avec un fichier inexistant : try : fichierIn=open("toto.txt",'r') except Exception as e : print(type(e)) sys.exit()

Exercice à choix multiple : Lien fichier
Si `fichier.txt` est un lien symbolique (crée avec la commande `ln -s`) vers un autre fichier, que va retourner le code ci-dessous ?
if os.path.isfile('fichier.txt'):
print('Ceci est un fichier')
Correct ! Si le lien symbolique pointe vers un fichier existant, alors ce test est positif.

Exercice à choix multiple : Lien dossier
Si `dossier` est un lien symbolique (crée avec la commande `ln -s`) vers un autre dossier, que va retourner le code ci-dessous ?
if os.path.isdir('dossier'):
print('Ceci est un dossier')
Correct ! Si le lien symbolique pointe vers un dossier existant, alors ce test est positif.

Exercice à choix multiple : Lien fichier
Quelle est la méthode pour écrire dans un fichier ?
Correct !

Questions souvent posées

Quels sont les différents mode d'ouverture et leurs spécificités ?

 

open(fichier, mode)
 

  • le mode `read` : ouvre le fichier en lecture seulement, c'est mode par défaut
  • le mode `write` : ouvre le fichier en écriture, si le fichier existe il sera écrasé
  • le mode `append` : ouvre le fichier en écriture, si le fichier existe les écritures s'ajoutent au fichier et ne l'écrase pas

Quelle est la meilleur manière de parcourir de très gros fichier ?

Utiliser une boucle `for` directement sur l'objet est la manière la plus rapide et qui utilise le moins de mémoire. Les méthodes `read()`, `readline()` et `readlines()`, en plus de nécessiter des actions supplémentaires, obligent à mettre l'intégralité du fichier en mémoire.

Exemples de questions de cours

  • Quelle est la syntaxe de la fonction `open()` ?
  • Quels sont les différents modes d'ouverture ?
  • Quels tests peut-on faire sur un fichier ?
  • Quel module faut-il importer pour faire des tests sur les fichiers ?
  • Quelle méthode permet d'écrire dans un fichier ?
  • Quelles sont les différentes méthodes pour lire un fichier ?
  • Quelles sont les différences entre les différentes méthodes de lecture ?

Des exercices pour s'entraîner

Exercice mêlé : Lecture
Remettez les instructions dans le bon ordre.
  • fichier.close()
  • fichier_in = input('Saisir le nom du fichier : ')
  • contenu = fichier.readlines()
  • fichier = open(fichier_in, 'r')
Correct !

Exercice mêlé : Écriture
Remettez les instructions dans le bon ordre.
  • fichier.close()
  • fichier = open(fichier_in, 'w')
  • fichier_in = input('Saisir le nom du fichier : ')
  • fichier.write('Bonjour tout le monde !')
Correct !

Exercice mêlé : Ajout
Remettez les instructions dans l'ordre.
  • for i in range(1,3):
  • fichier.write(item + '\n')
  • fichier.close()
  • fichier = open('fichier.txt', 'a')
  • item = input('Ajouter : ')
Correct !

Un résumé produit par des étudiants

Résumé du chapitre 6

Il a été réalisé par Maxence GRYMONPREZ et Alexandre GVOZDENOVIC, promo 2016-2017

Il est complet et bien présenté.