13 - Curso de Python - Leer y escribir ficheros en python

De ChuWiki

Cualquier duda suelo atender en este foro de python

Todo el código de este curso de Python gratuito está en github https://github.com/chuidiang/chuidiang-ejemplos/tree/master/PYTHON/curso-python. Puedes usar línea comandos python para ir siguiendo los ejemplos.

Anterior: 12 - Curso de Python - Try Exception -- Índice: Curso de Python -- Siguiente: Próximamente

Abrir y cerrar el fichero en python[editar]

En python los ficheros se abren con la función open(). Como primer parámetro se pasa el nombre del fichero y como segundo parámetro una cadena con caracteres que indican cómo debe abrirse el fichero. Varios ejemplos:

  • Abrir fichero de lectura : f = open("fichero.txt")
  • Abrir fichero de lectura : f = open("fichero.txt", "r")
  • Abrir fichero de lectura en binario : f = open("fichero.txt", "rb")
  • Abrir fichero para escribir desde cero : f = open ("fichero.txt", "w")
  • Abrir fichero para añadir al final : f = open ("fichero.txt", "a")
  • etc, etc

Respecto a los caracteres que se ponene como segundo parámetro:

  • Si no se pone segundo parámetro, se abre el fichero como lectura.
  • Si se pone el segundo parámetro, la primera letra del parámetro puede ser:
    • r abrir para lectura.
    • w abrir para escritura, machacando el fichero si existe.
    • a abrir el fichero para añadir al final más información.
    • x abrir el fichero para creación. Da fallo si el fichero existe.
  • Detrás de esta primera letra, se puede poner una b si queremos que el fichero se abra como fichero binario (bytes) y no como texto (caracteres). En un fichero binario se leerán/escribirán los bytes tal cual, sin hacer ningún tipo de interpretación. En un fichero de texto hay bytes que se interpretan, por ejemplo, el byte de valor 10 es un retorno de carro. Si un byte del fichero es el 241, abriéndolo como binario obtendremos un byte de valor 241. Abriéndolo como texto con codificación de caracteres utf-8, nos dará una eñe minúscula.
  • Finalmente, se puede añadir un símbolo + al final si queremos que el fichero se abra simultáneamente para lectura y escritura.

Encoding[editar]

Cuando abrimos el fichero en modo texto bien para leer, bien para escribir, tenemos opción de indicar cómo codificar los caracteres "extraños". Son caracteres extraños cosas como la eñe, las vocales con tilde, diéresis.... y máx extrasños aún, caracteres cirílicos, griegos, etc. La codificación es el mecanismo por el que una de estas letras se convierte a unos bytes concretos para escribir en el fichero y al revés. Hay muchas codificaciones posibles: ASCII, UTF-8, UTF-16, iso-8859-1 y un largo etcétera.

Si no indicas el tipo de codificación al abrir el fichero, se coge por defecto la del sistema oeprativo. Si trabajas en un ordenador y los ficheros que lees y escribes son propios de tu programa, no deberías tener problemas con los caracteres especiales de tu propio idioma. Sin embargo, si tu programa es multilingue y va a correr en distintos ordenadores con distintos sistemas operativos, es mejor fijar la codificación de caractares para no depender de la dels sistema operativo que no sabes cual va a ser. Y conviene elegir una que sea multi idioma. Una bastante habitual es UTF-8. La función open() llevaría un parámetro adicional

>>> f = open('prueba.txt','w',encoding='utf-8')
>>> f.write('ñ')
1
>>> f.close()

Hemos abierto un fichero con codificación utf-8 (parámetro encoding='utf-8'). Hemos escrito una eñe y hemos cerrado el fichero. Si abrimos el fichero con un editor normal en windows, veremos un caracter extraño

C:\> type prueba.txt
├▒

La razón es que windows usa otra codificación de caracteres que no es utf-8 y no sabe interpretar correctamente los bytes en el fichero como una eñe. Sin embargo, si leemos el fichero con nuestro programa, abriéndolo como utf-8, si lo tendremos correcto

>>> f = open ('prueba.txt', encoding='utf-8')
>>> print (f.readline())
ñ

>>> f.close()

Esto de la codificación de caracteres es algo que siempre da problemas de cabeza. El que escribe y el que lee el fichero no están de acuerdo en como está codificado y al final salen caracteres extraños. Por ello, tienes que tener claro quienes van a leer/escribir los ficheros para asegurarte que se van a entender. Si es sólo tu propio progama, asegúrate de usar siempre el mismo encoding. Si vas a escribir tú, pero va a leer el sistema operativo, asegúrate de usar el del sistema operativo, etc, etc.

Cierre del fichero[editar]

Para cerrarlo, basta llamar a f.close()

$ python
Python 2.5.2 (r252:60911, Apr 21 2008, 11:12:42) 
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open("kk.txt")
>>> f
<open file 'kk.txt', mode 'r' at 0x8199650>
>>> f.close()
>>> f
<closed file 'kk.txt', mode 'r' at 0x8199650>
>>> 

Más adelante hablamos sobre como leer todo el fichero con un blucle. Ahí comentamos una forma más correcta para asegurar el cierre del fichero.

Leer del fichero[editar]

Para leer del fichero, podemos usar las funciones f.read() y f.readline()

  • Lectura de todo el fichero de golpe : dato = f.read()
  • Lectura de 100 bytes : dato = f.read(100). Esta llamada vale para ficheros abiertos en modo binario o de texto.
  • Lectura de una línea completa : dato = f.readline(). Esta llamada es adecuada sólo para ficheros de texto, ya que un fichero binario no tiene por qué tener fines de línea. Y si los tiene, tampoco tiene mucho sentido leerl datos hasta un byte que coincida con el de fin de línea.
>>> f = open("kk.txt")
>>> f.read()
'hola\nmundo\n'
>>> f.close()
>>> f = open("kk.txt")
>>> dato = f.read(3)
>>> dato
'hol'
>>> f.close()
>>> f = open("kk.txt")
>>> dato = f.readline()
>>> dato
'hola\n'
>>> f.close()

Bucle para leer el fichero[editar]

Normalmente hacer un read() para leer todo el fichero de golpe es buena idea si el fichero es pequeño. Ten en cuenta que se cargará todo en memoria. Si el fichero es grande, conviene hacer un bucle para ir leyéndolo poco a poco. Por ejemplo, para un fichero de texto, esta podría ser una forma de leer línea por línea

f = open ('fichero.txt')

linea = f.readline()

while linea:
    print (linea, end='')
    linea = f.readline()

f.close()

Se abre el fichero. Se lee la primera línea. Se hace un bucle mientras la línea leída "existe" while linea:, es decir python interpreta esto como que no sea una cadena vacía ''. Tratamos la línea, en este caso sacándola por pantalla. Leemos la siguiente línea para repetir el bucle. Finalmente, una vez fuera del bucle, nos aseguramos de cerrar el fichero.

Se te pueden presentar aquí dos dudas.

¿Qué pasa si el fichero tiene una línea en blanco?. Bueno, aunque nosotros visualmente veamos una línea en blanco, realmente hay uno o dos bytes ahí que no vemos. El retorno de carro/fin de línea. En ficheros estilo linux este byte tiene el valor 10 y habitualmente en programación lo representamos como \n. Si hubiera una línea en blanco, la función readline nos devolvería una cadena "\n". Si sacamos esta cadena por pantalla, veríamos una línea vacía en blanco.

¿Qué es el segundo parámetro end='' del print(). Por un lado, al leer una línea del fichero en python, lee también al final de la línea el byte de retorno de carro. Si una línea de nuestro fichero es "Hola", python nos devolverá una cadena "Hola\n", con un retorno de carro al final. Si sacamos esto por pantalla de la forma normal print(linea), la función print() añadirá otro retorno de carro más. Por lo que la salida en pantalla de nuestro código será el fichero, pero con líneas en blanco adicionales entre cada dos líneas. En el siguiente bloque, los \n no los verías en pantalla, los ponemos para que queda más claro.

Fichero de texto\n                <- Línea leída por python del fichero, incluido el \n
\n                                <- \n añadido por print()
para las pruebas de lectura\n
\n
y escritura en python\n
\n

La forma de evitarlo es decirle a print() que no lo ponga. Eso se consigue con el segundo parámetro end=''. Si no hay segundo parámetro, print() añade al final por defecto un retorno de carro. Si ponemos el segundo parámetro, podemos poner una cadena cualquiera y la añadirá al final. En nuestro caso, cadena vacía para que no ponga nada.

Iterar sobre el fichero[editar]

Hay una segunda forma de leer el fichero. La variable con el fichero abierto es un iterator de python, por lo que tiene un método next() para leer el siguiente bloque de datos (línea si lo hemos abierto en modo texto, bytes si lo hemos abierto en modo binario). O bien, podemos ponerlo directamente en un bucle for

>>> f = open('fichero.txt')
>>> for linea in f:
...    print (linea, end='')
...
Fichero de texto
para las pruebas de lectura
y escritura en python
>>> f.close()

Asegurar el cierre del fichero[editar]

Sin embargo, como vimos en excepciones con python, puede suceder que en la lectura o escritura del fichero se produzca algún error que haga que nuestro programa termine. O también con el código que hagamos para tratar lo que leemos del fichero. Suele ser buena idea asegurarnos del cierre del fichero aunque haya errores. Una es la que hemos visto con excepciones con python, poniendo el cierre del fichero en finally, como se mencionó en el apartado de "Manejo de las Excepciones" del enlace anterior.

Hay otra forma alternativa de hacerlo, es con with en python. El código sería así

with open('fichero.txt') as f:
    linea = f.readline()
    while linea:
       print(linea)
       linea = f.readline()

Abrimos el fichero con with delante y as f detrás. Esto abre el fichero y lo guarda en una variable f. with ... : crea un bloque y el fichero permanecera abierto dentro de ese bloque. Una vez salgamos del bloque, el fichero se cierra automáticamente, pase lo que pase.

Dentro del bloque with  : leemos y tratamos el fichero. No necesitamos poner el f.close().

Escribir en el fichero[editar]

Para escribir el fichero desde cero, machando su contenido si lo hubiera

>>> f=open("kk.txt","w")
>>> f.write("machacando\n")
>>> f.close()
>>> f=open("kk.txt")
>>> f.read()
'machacando\n'
>>> f.close()

Para escribir sobre un fichero existente, añadiendo al final

>>> f = open ("kk.txt", "a")
>>> f.write("tras tres tris\n")
>>> f.close()
>>> f=open("kk.txt")
>>> f.read()
'machacando\ntras tres tris\n'
>>> f.close()


Moviéndose por el fichero[editar]

Con f.tell() podemos saber en qué posición estamos del fichero y con f.seek() podemos desplazarnos por él, para leer o escribir en una determinada posición.

  • f.seek(n) : Ir al byte n del fichero
  • f.seek(n,0) : Equivalente al anterior
  • f.seek(n,1) : Desplazarnos n bytes a partir de la posición actual del fichero
  • f.seek(n,2) : Situarnos n bytes antes del final de fichero.

El segundo parámetro en estos ejemplos es

  • Ninguno o 0 : la posición es relativa al principio del fichero
  • 1 : la posición es relativa a la posición actual
  • 2 : la posición es relativa al final del fichero y hacia atrás.

Un ejemplo

>>> f = open ("pom.xml")
>>> f.seek(0,2)
>>> f.tell()
632L
>>> f.seek(625)
>>> f.read()
'oject>\n'
>>> f.close()

En el ejemplo abrimos un fichero pom.xml, con f.seek(0,2) nos situamos al final del fichero, f.tell() nos dice la posición en la que estamos, que coincide con el número de bytes del fichero puesto que estamos al final del mismo. Con f.seek(625) nos situamos en la posición 625 del fichero. Leemos hasta final del fichero con f.read() y cerramos el fichero.

Ejemplo completo de lectura y escritura de fichero[editar]

A modo de ejemplo, el siguiente programa python abre un fichero y lo copia en otro

with open('fichero.txt') as origen:
    with open('copia.txt','w') as destino:
        linea = origen.readline()
        while linea:
            destino.write(linea)
            linea = origen.readline()

Anterior: 12 - Curso de Python - Try Exception -- Índice: Curso de Python -- Siguiente: Próximamente