Manipuler des fichiers en Python avec open

Maîtrisez open, with et les modes complexes (r+, w+, a+).

Publié le par Gabriel Trouvé (mis à jour le )
22 minutes

En Python, vous avez sûrement été amenés à manipuler des fichiers pour lire ou sauvegarder des données. Dans ce cadre, le context manager (with) et la fonction open sont incontournables pour éviter les fuites de mémoire.

De plus, les différents modes r, w, a, r+, w+ et a+ sèment souvent la confusion.

Pourquoi utiliser with open() ? Le context manager

En tant que débutant, on pourrait avoir tendance à ouvrir un fichier, faire nos opérations et, si on y pense, le fermer. En effet, il est tout à fait possible d'ouvrir et d'écrire dans un fichier sans passer par un context manager, bien que l'on utilise toujours la fonction open.

fichier = open("donnees.txt", "r", encoding="utf-8")
contenu = fichier.read()
fichier.close() 
PYTHON

Si on oublie de fermer le fichier avec la méthode close(), ou si une erreur survient avant cette ligne, il y a un risque de fuite de mémoire.

La solution à ce problème : le context manager 🔥, méthode qui est d'ailleurs recommandée par la PEP 8.

with open("donnees.txt", "r", encoding="utf-8") as fichier:
    contenu = fichier.read()
    # Traitement des données...
PYTHON

Le context manager s'occupe de l'allocation et de la libération des ressources pour nous : c'est propre et c'est sûr.

À noter

C'est une bonne pratique de spécifier l'encodage : encoding="utf-8". Cela permet d'éviter les problèmes d'accents, surtout lors d'échanges de fichiers entre Windows et Linux/macOS.

Les modes de base : lecture (r), écriture (w) et ajout (a)

Dans l'exemple précédent, nous avons vu que la fonction open prend un second argument : le mode. C'est là que ça devient intéressant 😅.

À noter

Avant de parler plus en détail des modes, nous allons aborder la notion de curseur. C'est l'endroit où Python va commencer à lire ou à écrire dans votre fichier. Selon le mode choisi, le curseur se positionnera différemment.

Le mode lecture (r)

Il s'agit du mode par défaut. Il permet seulement de lire le fichier et, si celui-ci n'existe pas, Python lève une erreur FileNotFoundError.
Le curseur est placé au début du fichier.

with open("mon_fichier.txt", "r", encoding="utf-8") as f:
    contenu = f.read()
PYTHON

Le mode écriture (w)

Il permet d'écrire dans le fichier. Si le fichier existe, il est écrasé et, s'il n'existe pas, il est créé.
Le curseur est placé au début.

with open("mon_fichier.txt", "w", encoding="utf-8") as f:
    f.write("Ceci est un nouveau contenu.")
PYTHON

Le mode ajout (a)

Contrairement au mode précédent, le mode ajout permet d'ajouter du contenu sans effacer l'existant. Si le fichier n'existe pas, il est créé.
Le curseur est placé automatiquement à la fin du fichier.

with open("logs.txt", "a", encoding="utf-8") as f:
    f.write("\nNouvelle entrée dans le journal.")
PYTHON

Jusqu'ici, tout allait bien. Maintenant, les choses vont se compliquer un peu... Nous allons nous pencher sur les modes avancés.

Le mode lecture et écriture (r+)

Ce mode permet de lire et d'écrire sans effacer le fichier. Comme pour le mode r, le fichier doit exister et le curseur est placé au début.
Ainsi, si vous écrivez dans le fichier, vous allez commencer l'écriture depuis le début, ce qui écrasera le texte déjà présent caractère par caractère.

# Imaginons un fichier contenant "Python"
with open("fichier.txt", "r+", encoding="utf-8") as f:
    f.write("Cy")
    # Le fichier contient maintenant "Cython"
    # "Py" a été remplacé par "Cy"
PYTHON

Le mode écriture et lecture (w+)

Dès l'ouverture, le contenu du fichier est effacé. Cela permet de repartir d'une feuille blanche, d'écrire des données et de les relire dans la foulée. Après l'écriture, il faut penser à replacer le curseur au début du fichier.

# Imaginon un fichier texte avec Python écrit dedans.
with open("fichier.txt", "w+", encoding="utf-8") as f:
    print(f.read())  # Affiche une chaîne vide, car w+ efface le contenu du fichier
    f.write("Nouveau texte")
    f.seek(0)  # Indispensable pour relire ce qu'on vient d'écrire
    print(f.read())  # Affiche "Nouveau texte"
PYTHON

Le mode ajout et lecture (a+)

Dans ce cas, le curseur est placé à la fin. Par conséquent, si vous cherchez à lire directement le fichier, vous n'obtiendrez rien, puisque vous êtes déjà au bout du document. L'écriture se fera toujours à la fin : même si vous déplacez le curseur avec seek() auparavant, l'écriture se fera quand même à la fin.

# Imaginons un fichier texte avec Python
with open("fichier.txt", "a+", encoding="utf-8") as f:
    print(f.read())  # Affiche une chaîne vide car le curseur est à la fin du fichier
    f.write("Ajout")
    f.seek(0)  # On revient au début pour lire tout le fichier
    print(f.read()) # Affiche "Python Ajout" car c'est le contenu du fichier après l'ajout
PYTHON

Qu'est-ce que seek() ?

La méthode seek() permet de déplacer le curseur pour la lecture ou l'écriture.
Revenons sur la syntaxe file.seek(offset, whence) :

  • offset correspond au nombre d'octets de déplacement (en mode texte, vous utiliserez principalement 0 pour revenir au début du fichier)

  • whence permet de définir le point de référence

Le point de référence (whence) fonctionne ainsi :

  • 0 pour le début du fichier (valeur par défaut)

  • 1 pour la position actuelle

  • 2 pour la fin du fichier

Attention

Jusqu'ici, nous avons ouvert nos fichiers en mode texte (ce qui est le mode par défaut). Très pratique, ce mode impose toutefois quelques restrictions avec la méthode seek(). En mode texte, il n'est pas possible de faire un déplacement relatif depuis la position courante ou depuis la fin du fichier.
En fait, en cas de déplacement arbitraire dans un fichier texte, le curseur peut tomber au milieu d'un caractère qui prend plusieurs octets.

with open("fichier.txt", "r", encoding="utf-8") as f:
    # Python ne peut pas garantir qu'on ne tombe pas au milieu d'un caractère
    f.seek(-6, 2)  # io.UnsupportedOperation: can't do nonzero end-relative seeks
PYTHON
with open("fichier.txt", "r", encoding="utf-8") as f:
    f.seek(1, 1)  # io.UnsupportedOperation: can't do nonzero cur-relative seeks
PYTHON

Le mode binaire

Pour une liberté totale de déplacement, ou pour travailler avec des fichiers non textuels, vous devez utiliser le mode binaire.
Il suffit simplement d'ajouter la lettre b au mode d'ouverture (exemple : rb).

Si vous avez bien suivi jusqu'ici, la méthode read() vous renverra un objet bytes et non plus une chaîne de caractères.

# Exemple : Lire les 6 derniers octets d'un fichier
with open("fichier.txt", "rb") as f:
    data = f.read()
    print(type(data))  # Affiche <class 'bytes'>
    print(data)  # Affiche des bytes : b'Python est g\xc3\xa9nial'

    # On peut se déplacer librement depuis la fin (2)
    # Reculer de 6 octets
    f.seek(-6, 2)
    data = f.read()

    # Si on sait que c'est du texte, on peut décoder manuellement
    print(data.decode("utf-8"))  # Affiche "énial"
PYTHON

Bravo, tu es prêt à passer à la suite

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.