HOWTO · Python

Escribir bytes en un archivo en Python

Este tutorial muestra cómo escribir bytes en un archivo binario en Python

En esta página

Para escribir bytes en un archivo con Python, llama a open() con el modo wb y pasa un objeto compatible con bytes al método write() del archivo. Usa un bloque with para que el archivo se cierre automáticamente. Si quieres añadir contenido al existente, usa ab.

Cada ejemplo crea sus archivos en un directorio temporal. Python elimina ese directorio cuando termina el bloque with del ejemplo. Para conservar un archivo, sustituye su ruta temporal por la de destino.

Cómo escribir bytes en un archivo con Python

La w de wb abre un archivo para escribir: lo crea si hace falta y trunca cualquier archivo existente en cuanto lo abre. La b selecciona el modo binario, por lo que Python escribe bytes sin codificación de texto ni traducción de saltos de línea.

Ejecuta este ejemplo para escribir datos y volver a leerlos:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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

En este archivo normal con búfer, write() devuelve el número de bytes escritos. El programa imprime esa cantidad y compara los datos guardados con los originales. La lectura se realiza después de que el bloque de escritura cierre el archivo y vacíe el búfer de Python. La extensión .bin es una convención para nombrar el archivo; el modo binario lo determina el argumento de modo.

Usa xb si quieres crear un archivo solo cuando todavía no exista. A diferencia de wb, este modo no permite sobrescribir un destino existente. Ninguno de los dos modos crea los directorios superiores que falten.

Escribir varias secuencias de bytes en un archivo

Mantén abierto el archivo mientras escribes los fragmentos sucesivos. Cada llamada a write() continúa desde la posición actual; abrir el archivo con wb dentro del bucle descartaría los fragmentos anteriores.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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)

Cada fragmento debe contener datos compatibles con bytes, como bytes, bytearray o una vista de búfer adecuada. También puedes pasar un iterable de secuencias de bytes a file.writelines(chunks). A pesar de su nombre, writelines() no añade separadores ni saltos de línea; inclúyelos en los fragmentos si los necesitas. Un bucle también permite procesar los fragmentos a medida que llegan, sin unir toda la carga en memoria.

Escribir un bytearray en un archivo

Un objeto bytes es inmutable, mientras que un bytearray permite cambiar bytes individuales o ampliar la secuencia antes de guardarla. Ambos se pueden escribir directamente en un archivo binario.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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)

Aquí, extend() añade otra secuencia y la asignación mediante índice cambia el primer byte. No hace falta convertirlo con bytes(payload) para escribirlo; usa esa conversión si necesitas un valor inmutable en otro contexto. Los cambios posteriores en el bytearray no actualizan el archivo automáticamente.

Escribir datos de BytesIO en un archivo

BytesIO, del módulo io, proporciona un flujo binario en memoria. Su método getbuffer() devuelve una vista de todo el búfer subyacente sin copiar su contenido a un objeto bytes independiente.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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 vista abarca todos los datos almacenados en el búfer, sin importar la posición actual del flujo. Mientras exista la vista, el objeto BytesIO no se puede redimensionar ni cerrar; los gestores de contexto anidados la liberan antes de cerrar el flujo. Usa buffer.getvalue() si prefieres obtener un valor bytes. Para copiar con buffer.read(), llama primero a buffer.seek(0) si quieres empezar desde el principio.

Añadir bytes o escribir en una posición concreta

Abre el archivo con ab para añadir bytes al final sin truncar el contenido existente. Este modo también crea el destino si aún no existe. Para sobrescribir bytes en un desplazamiento concreto de un archivo existente, usa r+b y el método seek() del objeto de archivo.

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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) mueve la posición al desplazamiento 2 en bytes, contado desde el principio. La siguiente escritura reemplaza dos bytes sin insertar datos ni eliminar el resto del contenido. Si necesitas quitar los bytes finales después de una sustitución más corta, usa truncate() de forma explícita.

r+b requiere que el archivo ya exista y conserva su contenido al abrirlo. w+b permite leer y escribir, pero primero trunca el archivo. Evita el modo de adición para actualizar una posición concreta: las escrituras se dirigen al final, y buscar otra posición no es una forma portable de cambiar ese comportamiento. Buscar más allá del final no amplía el archivo por sí solo; una escritura posterior puede ampliarlo, y el almacenamiento del espacio intermedio depende del sistema de archivos.

Búferes y escrituras grandes

Los archivos binarios normales abiertos con open() usan búfer de forma predeterminada. Una opción explícita como buffering=8192 solicita un tamaño para el búfer; no garantiza escrituras más rápidas ni obliga a que cada escritura al sistema operativo contenga exactamente 8192 bytes.

Para generar muchos datos, escribe fragmentos reutilizables en vez de construir un único objeto combinado de gran tamaño:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

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)

Este ejemplo muestra una configuración opcional del búfer y reutiliza un mismo fragmento. Elige el tamaño del búfer midiendo tu carga de trabajo real; no existe un tamaño óptimo para todos los casos. Al cerrar el archivo se vacía el búfer de Python. Si llamas a flush() antes, transfieres los datos almacenados al flujo subyacente, pero eso por sí solo no garantiza que queden guardados en el almacenamiento físico.

Preguntas frecuentes sobre cómo escribir bytes

¿Cómo vuelvo a leer los bytes? Abre el archivo con rb y llama a file.read(). El valor devuelto es bytes. Si el archivo es grande, lee fragmentos de tamaño fijo en vez de cargarlo entero de una vez.

¿Puedo escribir texto en modo binario? Primero codifícalo, por ejemplo con text.encode("utf-8") o bytes(text, "utf-8"). Para recuperar el texto, quien lo lea debe usar la codificación correspondiente. Si solo necesitas guardar texto, puede resultar más claro abrir el archivo en modo texto con encoding="utf-8".

¿Por qué write() produce un TypeError? Un flujo binario requiere datos compatibles con bytes. Pasarle directamente un str, un entero o una lista no cumple ese requisito. Codifica el texto o convierte una secuencia de valores enteros de bytes con bytes(values); cada entero debe estar entre 0 y 255.

¿Qué ocurre con una carga vacía? Escribir b"" no escribe ningún byte, pero al abrir un archivo existente con wb ya se ha truncado. Usa ab para conservar los datos existentes al añadir contenido, incluso si la nueva carga está vacía.

¿Por qué no se creó el destino? Comprueba que exista el directorio superior y que el proceso tenga permiso para escribir allí. Una ruta relativa se resuelve desde el directorio de trabajo actual del proceso. Gestiona en tu aplicación los errores OSError pertinentes y recuerda que la escritura o el cierre aún pueden fallar aunque el archivo se haya abierto correctamente.