HOWTO · Python

Ecrire des octets dans un fichier en Python

Ce tutoriel montre comment écrire des octets dans un fichier binaire en Python

Sur cette page

Pour écrire des octets dans un fichier en Python, appelez open() avec le mode wb, puis transmettez un objet de type bytes à la méthode write() du fichier. Utilisez un bloc with pour fermer automatiquement le fichier. Pour ajouter des données au contenu existant, choisissez plutôt ab.

Chaque exemple crée ses fichiers dans un répertoire temporaire. Python supprime ce répertoire à la fin du bloc with de l’exemple. Pour conserver un fichier, remplacez son chemin temporaire par celui de votre destination.

Écrire des octets dans un fichier en Python

Dans wb, le w ouvre un fichier en écriture : il le crée s’il n’existe pas et tronque un fichier existant dès son ouverture. Le b active le mode binaire : Python écrit les octets sans encodage de texte ni conversion des fins de ligne.

Exécutez cet exemple pour écrire des données, puis les relire :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "example.bin"
    data = b"This is some binary data."

    with open(path, "wb") as file:
        written = file.write(data)

    with open(path, "rb") as file:
        saved = file.read()

    print(written)
    print(saved == data)
25
True

Pour ce fichier classique avec tampon, write() renvoie le nombre d’octets écrits. Le programme affiche ce nombre et compare les données enregistrées aux données d’origine. La lecture a lieu après la fermeture du fichier par le bloc d’écriture, qui vide aussi le tampon Python. L’extension .bin relève d’une convention de nommage : c’est l’argument de mode qui active l’écriture binaire.

Utilisez xb pour créer un fichier uniquement s’il n’existe pas déjà. Contrairement à wb, ce mode refuse d’écraser une destination existante. Aucun de ces modes ne crée les répertoires parents manquants.

Écrire plusieurs séquences d’octets dans un fichier

Gardez le fichier ouvert pendant l’écriture des blocs successifs. Chaque appel à write() reprend à la position actuelle ; ouvrir le fichier avec wb à l’intérieur de la boucle effacerait les blocs précédents.

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from pathlib import Path
from tempfile import TemporaryDirectory

chunks = [b"First line.\n", b"Second line.\n", b"Third line.\n"]

with TemporaryDirectory() as directory:
    path = Path(directory) / "chunks.bin"
    with open(path, "wb") as file:
        for chunk in chunks:
            file.write(chunk)

Chaque bloc doit être constitué de données de type bytes, comme bytes, bytearray ou une vue de tampon adaptée. Vous pouvez aussi transmettre un itérable de séquences d’octets à file.writelines(chunks). Malgré son nom, writelines() n’ajoute ni séparateur ni saut de ligne : incluez-les dans les blocs si nécessaire. Une boucle permet également de traiter les blocs au fur et à mesure de leur arrivée, sans réunir toute la charge utile en mémoire.

Écrire un objet bytearray dans un fichier

Un objet bytes est immuable, tandis qu’un objet bytearray permet de modifier des octets individuels ou d’allonger la séquence avant de l’enregistrer. Les deux peuvent être écrits directement dans un fichier binaire.

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from pathlib import Path
from tempfile import TemporaryDirectory

payload = bytearray(b"Line 1\n")
payload.extend(b"Line 2\n")
payload[0] = ord("l")

with TemporaryDirectory() as directory:
    path = Path(directory) / "bytearray.bin"
    with open(path, "wb") as file:
        file.write(payload)

Ici, extend() ajoute une autre séquence et l’affectation par indice modifie le premier octet. Il n’est pas nécessaire d’utiliser bytes(payload) pour écrire le contenu ; effectuez cette conversion si vous avez besoin d’une valeur immuable ailleurs. Les modifications ultérieures de bytearray ne mettent pas automatiquement à jour le fichier.

Écrire les données de BytesIO dans un fichier

BytesIO, fourni par le module io, représente un flux binaire en mémoire. Sa méthode getbuffer() renvoie une vue de l’intégralité du tampon sous-jacent, sans copier son contenu dans un objet bytes distinct.

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from io import BytesIO
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "buffer.bin"
    with BytesIO() as buffer:
        buffer.write(b"Header\n")
        buffer.write(b"Payload\n")
        with buffer.getbuffer() as view:
            with open(path, "wb") as file:
                file.write(view)

La vue couvre toutes les données mises en tampon, quelle que soit la position actuelle du flux. Tant que cette vue existe, l’objet BytesIO ne peut être ni redimensionné ni fermé ; les blocs with imbriqués la libèrent avant de fermer le flux. Utilisez buffer.getvalue() si vous souhaitez obtenir un objet bytes. Pour copier les données avec buffer.read(), appelez d’abord buffer.seek(0) si la lecture doit commencer au début.

Ajouter des octets ou écrire à une position donnée

Ouvrez le fichier avec ab pour ajouter des octets à la fin sans tronquer le contenu existant. Ce mode crée également la destination si elle n’existe pas. Pour remplacer des octets à un décalage précis dans un fichier existant, utilisez r+b et la méthode seek() de l’objet fichier.

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "records.bin"
    with open(path, "wb") as file:
        file.write(b"ABCDEF")

    with open(path, "ab") as file:
        file.write(b"GH")

    with open(path, "r+b") as file:
        file.seek(2)
        file.write(b"xy")

seek(2) place la position à l’octet 2, en comptant depuis le début. L’écriture suivante remplace deux octets sans insérer de données ni supprimer la suite du contenu. Utilisez explicitement truncate() si vous devez supprimer les octets de fin après un remplacement plus court.

r+b exige un fichier existant et en conserve le contenu à l’ouverture. w+b permet la lecture et l’écriture, mais tronque d’abord le fichier. Évitez le mode ajout pour les mises à jour à une position précise : les écritures sont dirigées vers la fin, et utiliser seek() pour contourner ce comportement n’est pas portable. Se déplacer au-delà de la fin ne prolonge pas le fichier à lui seul ; une écriture ultérieure peut le prolonger, et le stockage de l’espace intermédiaire dépend du système de fichiers.

Mise en tampon et écritures volumineuses

Les fichiers binaires classiques ouverts avec open() sont mis en tampon par défaut. Un réglage explicite comme buffering=8192 demande une taille de tampon ; il ne garantit pas des écritures plus rapides et n’impose pas que chaque écriture du système d’exploitation contienne exactement 8192 octets.

Pour générer de grandes quantités de données, écrivez des blocs réutilisables au lieu de construire un seul objet volumineux :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

from pathlib import Path
from tempfile import TemporaryDirectory

chunk = b"record\n" * 1024

with TemporaryDirectory() as directory:
    path = Path(directory) / "large.bin"
    with open(path, "wb", buffering=8192) as file:
        for _ in range(100):
            file.write(chunk)

Cet exemple montre un réglage de tampon facultatif et réutilise un même bloc. Choisissez la taille du tampon en mesurant votre charge de travail réelle : il n’existe pas de taille optimale dans tous les cas. La fermeture du fichier vide le tampon Python. Un appel à flush() effectué plus tôt transfère les données mises en tampon vers le flux sous-jacent, mais ne garantit pas à lui seul leur persistance sur le support physique.

Questions fréquentes sur l’écriture d’octets

Comment relire les octets ? Ouvrez le fichier avec rb et appelez file.read(). La valeur renvoyée est un objet bytes. Pour un fichier volumineux, lisez des blocs de taille fixe plutôt que de tout charger en une seule fois.

Puis-je écrire du texte en mode binaire ? Encodez-le d’abord, par exemple avec text.encode("utf-8") ou bytes(text, "utf-8"). Pour retrouver le texte, le lecteur doit utiliser le même encodage. Si vous stockez uniquement du texte, une ouverture en mode texte avec encoding="utf-8" peut être plus claire.

Pourquoi write() renvoie-t-il une erreur TypeError ? Un flux binaire exige des données de type bytes. Passer directement une str, un entier ou une liste ne satisfait pas cette exigence. Encodez le texte ou convertissez une séquence d’entiers représentant des octets avec bytes(values) ; chaque entier doit être compris entre 0 et 255.

Que se passe-t-il avec une charge utile vide ? L’écriture de b"" n’ajoute aucun octet, mais l’ouverture d’un fichier existant avec wb l’a déjà tronqué. Utilisez ab pour conserver les données existantes lors d’un ajout, même si la nouvelle charge utile est vide.

Pourquoi la destination n’a-t-elle pas été créée ? Vérifiez que son répertoire parent existe et que le processus a le droit d’y écrire. Un chemin relatif est résolu à partir du répertoire de travail actuel du processus. Dans votre application, gérez les erreurs OSError pertinentes et gardez à l’esprit qu’une écriture ou une fermeture peut échouer même après l’ouverture réussie du fichier.