Apéndice G — Gestión de archivos.

Objetivo. Revisar la forma básica de gestionar archivos.

G.1 La función open().

La función incorporada para gestionar archivos es open(). Esta función toma dos parámetros: el nombre del archivo y el modo. Existen cuatro diferentes modos:

  • "r" - Read - Default value. Abre el archivo para lectura. Se produce un error si el archvio no existe.
  • "a" - Append - Abre el archivo para agregar información. Si el archivo no existe, lo crea.
  • "w" - Write - Abre el archivo para escritura. Si el archivo no existe, lo crea. Si el archivo existe, lo sobreescribe.
  • "x" - Create - Crea el archivo, regresa un error si el archivo existe.

Adicionalmente se puede especificar si el archivo se abre en modo texto o binario:

  • "t" - Text - Valor por omisión.
  • "b" - Binary

G.2 Abrir un archivo para lectura.

f = open('gatos.txt')
print(f)
print(type(f))
<_io.TextIOWrapper name='gatos.txt' mode='r' encoding='cp1252'>
<class '_io.TextIOWrapper'>

En este ejemplo f es un descriptor del archivo que se acaba de abrir y contiene información como el nombre del archivo, el modo en que se abrió y la codificación. El tipo es _io.TextIOWrapper.

G.3 Leer una línea del archivo.

Para obtener información del archivo existen varios métodos, particularmente en readline() que lee una línea del archivo y avanza a la siguiente.

f.readline()
'     Persa       2.3\n'
f.readline()
'    Sphynx       3.5\n'
l1 = f.readline() # se puede almacenar lo que se lee en una variable
print(l1)
   Ragdoll       5.4
f.readline()
'    Siamés       2.5'
f.readline()
''

G.4 Cerrar un archivo.

Siempre que se abra un archivo, ya sea para lectura o escritura, es importante cerrarlo cuando ya no se esté usando.

Para cerrar un archivo se usa el método close():

f.close()

G.5 Leer todas las líneas del archivo.

También es posible leer todo el contenido del archivo de un solo paso con la función readlines().

f = open('gatos.txt')
lines = f.readlines()
print(lines)
f.close()
['     Persa       2.3\n', '    Sphynx       3.5\n', '   Ragdoll       5.4\n', '    Siamés       2.5']

G.6 Abrir un archivo para escritura.

Si queremos abrir un archivo para escritura usamos el modo w.

Primero vamos a abrir un archivo y leer su información:

f1 = open('gatos.txt','r')
lineas = f1.readlines()
print(lineas)
f1.close()
['     Persa       2.3\n', '    Sphynx       3.5\n', '   Ragdoll       5.4\n', '    Siamés       2.5']

Ahora abrimos un segundo archivo para escribir información en él:

f2 = open('gatitos.txt','w')
f2.writelines(lineas)
f2.close()

Revisa que se haya generado el archivo gatitos.txt en tu directorio de trabajo y checa que tenga el mismo contenido que el archivo gatos.txt. Con el siguiente código abrimos el archivo creado y vemos su contenido:

f2 = open('gatitos.txt','r')
print(f2.readlines())
f2.close()
['     Persa       2.3\n', '    Sphynx       3.5\n', '   Ragdoll       5.4\n', '    Siamés       2.5']

G.7 Abrir un archivo para agregar información al final.

Si ya existe un archivo, es posible agregarle información como sigue:

# Abrimos un archivo para insertar información.
f3 = open('gatitos.txt', 'a')

# Esta es la información que se va a agregar
linea_nueva = "\n{:>10s}{:>10.1f}\n".format("Eléctrico", 3.7)

# Se escribe la información.
n = f3.write(linea_nueva)

# Cerramos el archivo
f3.close()

Revisa el nuevo contenido del archivo gatitos.txt en tu directorio de trabajo. La nueva información debió escribirse al final del archivo. De igual manera podemos verificar el contenido con el siguiente código:

f3 = open('gatitos.txt','r')
print(f3.readlines())
f3.close()
['     Persa       2.3\n', '    Sphynx       3.5\n', '   Ragdoll       5.4\n', '    Siamés       2.5\n', ' Eléctrico       3.7\n']

Observa que el archivo ya contiene la nueva información.

G.8 Abrir un archivo para insertar información en cualquier lugar.

# Abrimos el archivo en modo 'r+'
f4 = open('gatitos.txt', "r+")

# Leemos el contenido del archivo
contenido = f4.readlines()

# Calculamos la mitad del archivo (aprox), debe ser un entero
indice = len(contenido) // 2

# Generamos nueva información
linea_nueva = "{:>10s}{:>10.1f}\n".format("Birmano", 3.2)

# Agregamos la información a la mitad del archivo
contenido.insert(indice, linea_nueva)

# Regresamos al inicio del archivo
f4.seek(0)

# Escribimos todas las líneas del archivo.
f4.writelines(contenido)

f4.close()

Revisa el nuevo contenido del archivo gatitos.txt en tu directorio de trabajo. La nueva información debió escribirse a la mitad del archivo aproximadamente.

Usamos el siguiente código para checar el archivo con la nueva información:

f4 = open('gatitos.txt','r')
print(f4.readlines())
f4.close()
['     Persa       2.3\n', '    Sphynx       3.5\n', '   Birmano       3.2\n', '   Birmano       3.2\n', '   Ragdoll       5.4\n', '    Siamés       2.5\n', ' Eléctrico       3.7\n']

G.9 Gestores de contexto.

Los gestores de contexto en Python son una manera de gestionar recursos de forma eficiente y segura.

Se utilizan con la palabra clave with, que garantiza que ciertos recursos se inicialicen y liberen correctamente, incluso si ocurre una excepción.

Estos recursos pueden incluir archivos, conexiones de red, bloqueos de threads, etc.

Por ejemplo:

with open('contexto_ejemplo', 'w') as archivo_abierto:
    archivo_abierto.write('En este ejemplo, todo se realiza con un gestor de contexto.')

Lo que realiza la operación anterior es:

  1. Abre el archivo contexto_ejemplo.
  2. Escribe algo en el archivo,
  3. Cierra el archivo. Si ocurre algún error mientras se escribe en el archivo, entonces se intenta cerrar el archivo.

El código es equivalente a:

archivo_abierto = open('contexto_ejemplo', 'w')
try:
    archivo_abierto.write('En este ... contexto!')
finally:
    archivo_abierto.close()
Tip

Esta forma de abrir un archivo, manipular su información y cerrarlo, usando un gestor de contexto (with), es la más recomendada.

Es posible implemetar nuestros propios gestores de contexto. Para ello se requiere un conocimiento más profundo de Programación Orientada a Objetos.

NotaNota.

En el ejemplo anterior se usó la construcción try:finally: que se usa para gestionar errores. Esto se revisa en detalle en el Apéndice Q.

El propósito de un gestor de contexto es asegurarse de que las acciones de “entrada” y “salida” de un contexto se manejen adecuadamente. El contexto se refiere a cualquier bloque de código que necesita realizar alguna configuración al inicio (como abrir un archivo o adquirir un recurso) y luego limpiar al final (como cerrar el archivo o liberar el recurso).

Ventajas de los gestores de contexto.

  1. Código más limpio: No tienes que preocuparte por cerrar recursos manualmente.
  2. Manejo seguro de excepciones: Incluso si ocurre una excepción dentro del bloque with, el recurso se libera correctamente.
  3. Legibilidad: El código es más claro en cuanto a cuándo comienza y termina el uso de un recurso.

¿Cómo funcionan?

Los gestores de contexto implementan los métodos especiales __enter__ y __exit__: - __enter__(): Este método es llamado al inicio del bloque with. Se utiliza para establecer el recurso o la configuración inicial. - __exit__(exc_type, exc_value, traceback): Este método es llamado al final del bloque with, independientemente de si se produjo una excepción. Se utiliza para liberar o limpiar el recurso.