Saltar a contenido

9. Archivos

Un archivo necesita ser abierto antes de que pueda ser procesado por un programa, y debe ser cerrado cuando el procesamiento termine.

El abrir un archivo lo asocia con el stream, que es una representación abstracta de los datos físicos almacenados en los medios. La forma en que se procesa el stream se llama modo de apertura

Dependiendo del contenido del archivo físico, se pueden usar diferentes clases de Python para procesar archivos. En general, BufferedIOBase es capaz de procesar cualquier archivo, mientras que TextIOBase es una clase especializada dedicada al procesamiento de archivos de texto (es decir, archivos que contienen textos visibles para humanos divididos en líneas usando marcadores de nueva línea). Por lo tanto, los streams se pueden dividir en binarios y de texto.

Abrir stream

open(nombre_archivo, modo=modo_apertura, codificación=codificacion_de_texto)
stream = open(file, mode = 'r', encoding = None)

El nombre de la función (open) habla por si mismo; si la apertura es exitosa, la función devuelve un objeto stream; de lo contrario, se genera una excepción (por ejemplo, FileNotFoundError si el archivo que vas a leer no existe).

El primer parámetro de la función (file) especifica el nombre del archivo que se asociará al stream.

El segundo parámetro (mode) especifica el modo de apertura utilizado para el stream; es una cadena llena de una secuencia de caracteres, y cada uno de ellos tiene su propio significado especial (más detalles pronto).

El tercer parámetro (encoding) especifica el tipo de codificación (por ejemplo, UTF-8 cuando se trabaja con archivos de texto).

La apertura debe ser la primera operación realizada en el stream.

# Se abre el archivo tzop.txt en modo lectura, devolviéndolo como un objeto del tipo archivo:
stream = open("tzop.txt", "rt", encoding = "utf-8")

# Se imprime el contenido del archivo:
print(stream.read()) 

Modos

r modo de apertura: lectura

  • El stream será abierto en modo lectura.
  • El archivo asociado con el stream debe existir y tiene que ser legible, de lo contrario la función open() generará una excepción.

w modo de apertura: escritura

  • El stream será abierto en modo escritura.
  • El archivo asociado con el stream no necesita existir. Si no existe, se creará; si existe, se truncará a la longitud de cero (se borra); si la creación no es posible (por ejemplo, debido a permisos del sistema) la función open() generará una excepción.

a modo de apertura: adjuntar

  • El stream será abierto en modo adjuntar.
  • El archivo asociado con el stream no necesita existir; si no existe, se creará; si existe, el cabezal de grabación virtual se establecerá al final del archivo (el contenido anterior del archivo permanece intacto).

r+ modo de apertura: lectura y actualización

  • El stream será abierto en modo lectura y actualización.
  • El archivo asociado con el stream debe existir y tiene que permitir escritura, de lo contrario la función open() generará una excepción.
  • Se permiten operaciones de lectura y escritura en el stream.

w+ modo de apertura: escritura y actualización

  • El stream será abierto en modo escritura y actualización.
  • El archivo asociado con el stream no necesita existir; si no existe, se creará; el contenido anterior del archivo permanece intacto.
  • Se permiten operaciones de lectura y escritura en el stream.

x modo de apertura: creación exclusiva.

  • Si el archivo ya existe, la función open() generará una excepción.

Streams pre-abiertos

import sys

sys.stdin # entrada estándar)
sys.stdout # salida estándar
sys.stderr # salida de error estándar

Cerrar streams

La última operación realizada en un stream (esto no incluye a los streams stdin, stdout, y stderr pues no lo requieren) debe ser cerrarlo.

Esa acción se realiza mediante un método invocado desde dentro del objeto del stream: stream.close().

Gestión de errores en streams

El objeto IOError está equipado con una propiedad llamada errno (el nombre viene de la frase error number, número de error) y puedes acceder de la siguiente manera:

try:
    # Algunas operaciones con streams.
except IOError as exc:
    print(exc.errno)

constantes seleccionadas útiles para detectar errores en los streams:

errno.EACCES→ Permiso denegado

El error se produce cuando intentas, por ejemplo, abrir un archivo con atributos de solo lectura para abrirlo.

errno.EBADF→ Número de archivo incorrecto

El error se produce cuando intentas, por ejemplo, operar un stream sin abrirlo.

errno.EEXIST→ Archivo existente

El error se produce cuando intentas, por ejemplo, cambiar el nombre de un archivo con su nombre anterior.

errno.EFBIG → Archivo demasiado grande

El error ocurre cuando intentas crear un archivo que es más grande que el máximo permitido por el sistema operativo.

errno.EISDIR → Es un directorio

El error se produce cuando intentas tratar un nombre de directorio como el nombre de un archivo ordinario.

errno.EMFILE → Demasiados archivos abiertos

El error se produce cuando intentas abrir simultáneamente más streams de los aceptables para el sistema operativo.

errno.ENOENT → El archivo o directorio no existe

El error se produce cuando intentas acceder a un archivo o directorio inexistente.

errno.ENOSPC → No queda espacio en el dispositivo

El error ocurre cuando no hay espacio libre en el dispositivo.

strerror

strerror() proviene del módulo os y espera solo un argumento: un número de error.

from os import strerror

try:
    s = open("c:/users/user/Desktop/file.txt", "rt")
    # El procesamiento va aquí.
    s.close()
except Exception as exc:
    print("El archivo no pudo ser abierto:", strerror(exc.errno))

Leer contenido

Para leer el contenido de un archivo, se pueden utilizar los siguientes métodos:

  • read(number): lee el número de carácteres/bytes del archivo y los retorna como una cadena, es capaz de leer todo el archivo a la vez.

  • readline(): lee una sola línea del archivo de texto.

  • readlines(number): lee el número de líneas del archivo de texto; es capaz de leer todas las líneas a la vez.

  • readinto(bytearray): lee los bytes del archivo y llena el bytearray con ellos.

El método open() devuelve un objeto iterable que se puede usar para recorrer todas las líneas del archivo dentro de un bucle for. Por ejemplo:

for line in open("file", "rt"):
    print(line, end='')

Escribir contenido

Para escribir contenido nuevo en un archivo, se pueden utilizar los siguientes métodos:

  • write(string): escribe una cadena a un archivo de texto.

  • write(bytearray): escribe todos los bytes de un bytearray a un archivo.

Trabajando con archivos reales

Por ejemplo, si estás utilizando un sistema operativo Unix/Linux configurado para usar UTF-8 como una configuración de todo el sistema, la función open() puede verse de la siguiente manera:

stream = open('file.txt', 'rt', encoding='utf-8')

Donde el argumento de codificación debe establecerse en un valor dentro de una cadena que representa la codificación de texto adecuada (UTF-8, en este caso).

Consulta la documentación de tu sistema operativo para encontrar el nombre de codificación adecuado para tu entorno.

Lectura

read() → Leer un número determinado de caracteres (incluso solo uno) del archivo y devolverlos como una cadena. Leer todo el contenido del archivo y devolverlo como una cadena. Si no hay nada más que leer (el cabezal de lectura virtual llega al final del archivo), la función devuelve una cadena vacía.

readline() → manejar el contenido del archivo como un conjunto de líneas, no como un montón de caracteres

readlines(), se invoca sin argumentos, intenta leer todo el contenido del archivo y devuelve una lista de cadenas, un elemento por línea del archivo. Puedes pasarle un nº de bytes como parámetro.

from os import strerror

try:
    counter = 0
    stream = open('text.txt', "rt")
    content = stream.read()
    for char in content:
        print(char, end='')
        counter += 1
    stream.close()
    print("\n\nCaracteres en el archivo:", counter)
except IOError as e:
    print("Se produjo un error de E/S:", strerr(e.errno))
from os import strerror

try:
    character_counter = line_counter = 0
    stream = open('text.txt', 'rt')
    line = stream.readline()
    while line != '':
        line_counter += 1
        for char in line:
            print(char, end='')
            character_counter += 1
        line = stream.readline()
    stream.close()
    print("\n\nCaracteres en el archivo:", character_counter)
    print("Líneas en el archivo:     ", line_counter)
except IOError as e:
    print("Se produjo un error de E/S:", strerror(e.errno))
from os import strerror

try:
    character_counter = line_counter = 0
    stream = open('text.txt', 'rt')
    lines = stream.readlines(20)
    while len(lines) != 0:
        for line in lines:
            line_counter += 1
            for char in line:
                print(char, end='')
                character_counter += 1
        lines = stream.readlines(10)
    stream.close()
    print("\n\nCaracteres en el archivo:", character_counter)
    print("Líneas en el archivo:     ", line_counter)
except IOError as e:
    print("Se produjo un error de E/S:", strerror(e.errno))

la función open() en modo de texto devuelve un objeto que es una instancia de la clase iterable.

El protocolo de iteración definido para el objeto del archivo es muy simple: su método next solo devuelve la siguiente línea leída del archivo.

Además, puedes esperar que el objeto invoque automáticamente a close() cuando cualquiera de las lecturas del archivo lleguen al final del archivo.

from os import strerror

try:
  character_counter = line_counter = 0
  for line in open('text.txt', 'rt'):
    line_counter += 1
    for char in line:
      print(char, end='')
      character_counter += 1
  print("\n\nCaracteres en el archivo: ", character_counter)
  print("Líneas en el archivo:     ", line_counter)
except IOError as e:
  print("Se produjo un error de E/S:", strerror(e.errno))

Última actualización: 2022-11-01