Python: Aprendiendo a escribir

Objetivo: aprender el modo que tiene Python de escribir texto en un fichero.

Si te has leído el anterior artículo de esta serie, probablemente habrás intuido la temática del artículo hoy: la escritura en ficheros de texto.

Todo comenzó un día de octubre, cuando un nuevo y sofisticado ente entró en escena:

fichero = open('pruebas.txt')

Esta instrucción creaba un nuevo objeto, una abstracción del fichero de texto real en disco, pruebas.txt, que nos permitía realizar operaciones de lectura sobre él.

En realidad, ese comando no es más que una forma simplificada de:

fichero = open('pruebas.txt', 'rt')

O incluso:

fichero = open('pruebas.txt', 'r')

Las letras entrecomilladas, como segundo parámetro de la función open(), indican el modo en que se abrirá el fichero. La r (de read) y la t (de text) hacen referencia a que se trata de un fichero de texto y que sólo realizaremos operaciones de lectura, no estando, por lo tanto, permitida su modificación.

Cuando no se especifica el modo de apertura, se presupone la opción por defecto, que es precisamente esta: texto y lectura.

Hoy vamos a realizar la operación inversa: la escritura de ficheros de texto. Para ello presentaremos un nuevo modo: ‘w’, forma simplificada de ‘wt’.

Introduce la siguiente instrucción en un intérprete interactivo:

>>> fichero = open('prueba2.txt', 'w')

Lo primero que debes saber del modo ‘w’ es el efecto de esta operación: si el fichero indicado no existe, lo creará (naturalmente, vacío), y si ya existe lo sobreescribirá, perdiendo su contenido (y dejándolo, por lo tanto, vacío también).

El tipo de objeto es el mismo que en el ejemplo del artículo anterior:

>>> type(fichero)
<class '_io.TextIOWrapper'>

Con la particularidad de que las operaciones de lectura no están permitidas:

>>> fichero.read()
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    fichero.read()
io.UnsupportedOperation: not readable

El modo ‘w’, de write, nos permite escribir en ese fichero. El método estándar para realizar esto es write():

>>> fichero.write('Serie: La casa de la pradera\nAño: ni lo recuerdo, \
yo era pequeño\n\n¿La repondrán? ')
81

He facilitado, entre comillas, un string con el texto que quiero introducir. Lo podría haber hecho línea a línea, con llamadas a write() sucesivas, pero he optado por incluirlo todo en uno solo. Observa que, para separar una línea de la siguiente necesito hacer uso del carácter de escape \n.

La barra \ que he escrito al final de la primera línea es para decirle al intérprete que voy a continuar en la siguiente línea, de modo que quede más presentable el código. No forma parte del string.

El método write() devuelve un número con el total de caracteres que han sido escritos, 81 en este caso.

Las escrituras sucesivas continúan justo en el punto donde terminó la última:

>>> fichero.write('Quién sabe.')
11

Comprobemos es aspecto de nuestro archivo de texto final. Para ello, primero hay que cerrar el fichero, indicando que hemos dejado de trabajar con él, liberando la memoria ocupada y haciendo que se vuelque la información efectivamente en el disco:

>>> fichero.close()

Este es el contenido de prueba2.txt tras estas operaciones:

Serie: La casa de la pradera
Año: ni lo recuerdo, yo era pequeño

¿La repondrán? Quién sabe.

La escritura puede ser, desde luego, en cualquier parte del fichero, no necesariamente a continuación de la última operación. Podemos desplazarnos a cualquier punto empleando el método seek() que presentamos brevemente en el último artículo. Veremos esto a su debido momento.

Una operación frecuente en el trabajo con ficheros en Python consiste en volcar a un archivo de texto el contenido de una secuencia. Considera, por ejemplo, la siguiente lista:

>>> a = ['Litio\n', 'Sodio\n', 'Potasio\n']

Nuestra misión consistirá en crear un fichero de texto en el que figure cada elemento en una línea diferente.

Con lo explicado hasta el momento tenemos recursos suficientes para resolvere el problema: realizamos una iteración sobre la lista escribiendo, en cada pasada, el elemento correspondiente:

>>> fichero = open('prueba2.txt', 'w')  #El fichero antiguo se perderá
>>> for elemento in a:
  fichero.write(elemento)

  
6
6
8
>>> fichero.close()

Los tres números devueltos por el intérprete de comandos son, como hemos dicho, el número de caracteres escritos tras cada operación. En un programa independiente no aparecerían.

El fichero prueba2.txt tiene el contenido buscado:

Litio
Sodio
Potasio

Cada elemento de la lista ya contenía el \n al final, de modo que la siguiente escritura quedaba preparada en el punto adecuado. En el caso de no fuera así deberías facilitarlo tú. Por ejemplo:

>>> b = ['Fluor', 'Cloro', 'Bromo', 'Iodo']
>>> fichero = open('prueba2.txt', 'w')
>>> for elemento in b:
  fichero.write(elemento + '\n')

  
6
6
6
5
>>> fichero.close()

El archivo final contiene cada elemento en una línea distinta, como puedes comprobar:

Fluor
Cloro
Bromo
Iodo

En lugar de

fichero.write(elemento + '\n')

podemos recurrir a la elegancia de una especificación de formato:

fichero.write('%s\n' % elemento)

Fino, ¿verdad?

Para mayor elegancia aún disponemos del método writelines(). ¿Recuerdas, en el artículo anterior, que usábamos readlines() para volcar un archivo de texto a una lista? Precisamente, writelines() hace justo lo contrario: descarga a fichero el contenido de la lista.

Volvamos a la lista de metales alcalinos, en la que cada elemento se finalizaba con \n:

>>> a
['Litio\n', 'Sodio\n', 'Potasio\n']

El método writelines() vuelca a un un archivo el contenido de una lista (o cualquier secuencia, en general). Cada elemento se escribe a continuación del anterior:

>>> fichero = open('prueba2.txt', 'w')
>>> fichero.writelines(a)
>>> fichero.close()

—-

Litio
Sodio
Potasio

La separación de líneas ha sido posible porque cada elemento de la lista contenía ya el \n final.

Esto es todo por hoy. Entendidas las técnicas básicas de lectura y escritura, estamos ya en condiciones de realizar operaciones más avanzadas.

Javier Montero Gabarró


Python: Aprendiendo a escribir


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Aprendiendo a leer

Objetivo: aproximación al trabajo con ficheros en Python, mostrando cómo leer el contenido de un archivo de texto.

Como programador, necesitas familiarizarte cuanto antes con el trabajo con ficheros. Con frecuencia tu aplicación deberá recuperar información de un fichero para su procesamiento, o bien almacenará en él el resultado de ese proceso. Es común también el intercambio de información con el exterior en ambos sentidos: la aplicación se nutre de datos externos almacenados en ficheros y genera información que se guarda nuevamente ellos después.

Nos aproximaremos al trabajo con ficheros en Python de un modo gradual y aprenderemos a realizar las tareas más típicas partiendo de lo más simple: la lectura de un archivo de texto.

Supongo que ya conoces la diferencia entre los ficheros de texto y los binarios. Expresada de un modo simple, los primeros pueden ser leídos empleando un editor de texto plano, como gedit en Linux o el bloc de notas de Windows. Más técnicamente, podríamos decir que los ficheros de texto mantienen una codificación estándar que permite la asociación de cada byte (o un grupo de ellos) con un determinado carácter de texto, mientras que en los binarios el significado de cada byte es determinado por la propia aplicación, pudiendo representar cualquier tipo de entidad.

Ya sabes que para Python todo son objetos y, naturalmente, los ficheros también. Para que podamos interactuar con un fichero, Python crea una abstracción, un objeto, a través del cual se nos ofrece una serie de métodos para que podamos trabajar con él. Hay métodos para leer, escribir o modificar el cursor (la posición en la que se realizará la lectura o escritura), por indicar algunos.

Lo primero que debemos aprender es a crear esa abstracción, el objeto sobre el cual trabajaremos para interacturar con el fichero físico real. Es lo que se conoce como abrir el fichero.

Para hacerlo disponemos de la función open(), que usaremos del siguiente modo:

nombre_del_objeto = open(fichero_real, modo_de_apertura)

nombre_del_objeto es el nombre con el que designaremos la abstracción que envolverá al fichero_real. Dependiendo del valor que indiquemos en modo_de_apertura Python construirá un tipo de objeto u otro y determinará qué tipo de operaciones podemos realizar con él.

Iremos conociendo los distintos modos en los sucesivos artículos, pero por el momento quédate con la idea de que, cuando no se especifica un modo, Python sobreentiende que se trata de un fichero tipo texto y que sólo vas a realizar operaciones de lectura. Esto es justo lo que pretendemos lograr hoy, ser capaces de leer el contenido de un archivo de texto.

Créate un fichero de pruebas y abre un intérprete de comandos en el mismo directorio.

En este ejemplo, he creado el fichero pruebas.txt, con el siguiente contenido:

Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Observa que se trata de un fichero de cinco líneas en el que he dejado la tercera expresamente en blanco.

Para leer el fichero, la primera acción a realizar es, como hemos visto, abrirlo:

>>> fichero = open('pruebas.txt')

He elegido como nombre del objeto, fichero, sin complicarme la vida más. Entre comillas, como argumento de la función open() figura el nombre del archivo. Si no se encontrase en el mismo directorio en el que hemos ejecutado Python, deberíamos especificar su path completo.

Recuerda lo dicho anteriormente: si no indicamos un segundo parámetro con el modo de apertura, se sobreentiende el siguiente: texto y lectura.

Si tienes curiosidad por saber qué tipo de objeto ha creado Python, pregúntaselo:

>>> type(fichero)
<class '_io.TextIOWrapper'>

Que es algo así como un “envoltorio de entrada y salida texto”.

Existen diversas formas de leer el fichero. Una de ellas es aprovecharnos de una particularidad muy interesante: podemos iterar sobre un fichero de texto recorriéndolo línea a línea, de modo semejante al que iteramos recorriendo una lista de principio a fin con el bucle for.

Ensayemos lo siguiente:

>>> for linea in fichero:
  print(linea)

  
Comienza el fichero con una mención a la casa de la pradera.

La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.

Es una verdadera lástima que esta sea la última línea.

Salvo por el detalle de que ha intercalado una línea en blanco adicional entre cada línea, el resultado es bastante decente.

Enseguida veremos cómo solucionar esto, pero antes necesito que observes un comportamiento curioso.

Vamos a intentar iterar una segunda vez y veamos qué ocurre:

>>> for linea in fichero:
  print(linea)

  
>>> 

No ha devuelto absolutamente nada. La iteración está agotada.

Python, paralelamente al proceso de lectura, actualiza un cursor indicando cúal es el siguiente elemento a leer. Como ya ha llegado al final, un nuevo intento de lectura fracasa, pues no hay nada más que leer.

¿Significa esto que no podemos leer un fichero varias veces? En absoluto. Existe un método que nos permite mover el cursor de lectura al punto deseado.

>>> fichero.seek(0)
0

Esta instrucción nos posiciona nuevamente al comienzo del fichero (carácter en la posición 0). La trataremos con detalle en otro momento, pero por ahora es suficiente con que retengas este uso.

Ya estamos en condiciones de realizar una segunda lectura, pero esta vez lo haremos sin que se impriman las líneas en blanco adicionales.

¿A qué se debe que haya dos líneas en blanco?

Python distingue una línea de otra terminándola con el carácter de nueva línea (\n). Pero, además, la función print() agrega siempre, por defecto, otro carácter de fin de línea al final, de modo que cada impresión queda separada de la anterior en una línea diferente. Por eso encontramos los dos saltos de línea: el que trae cada línea propiamente dicha más el que agrega la función print().

Para esta segunda lectura vamos a modificar la función print(), agregando un parámetro con el carácter o caracteres que deseamos que agregue al final de cada impresión, en lugar de la opción por defecto, el salto de línea. Para indicar que no queremos que agregue nada, el uso de print() debe ser el siguiente:

print(linea, end='')

De modo que nuestra iteración por líneas ahora produciría el resultado deseado:

>>> for linea in fichero:
  print(linea, end='')

  
Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Voy a presentarte a continuación un método interesante que te permite leer el fichero de una sola vez: read().

Posiciónate de nuevo al comienzo del fichero, que habrá quedado exhausto tras la lectura anterior.

>>> fichero.seek(0)
0

Y ejecuta esta nueva instrucción:

>>> fichero.read()
'Comienza el fichero con una mención a la casa de la pradera.\nLa segunda línea suele hallarse después de la primera.\n\nEsta es la cuarta línea, en la tercera había una línea en blanco.\nEs una verdadera lástima que esta sea la última línea.\n'

Devuelve un string muy largo con el contenido del fichero (probablemente tendrás que usar la barra de desplazamiento al ver esto en el navegador, pues el contenido se muestra en una única línea).

Lo importante es que se aprecia bien la estructura del fichero, con los \n separando cada línea. Fíjate también en la línea en blanco, en la posición donde está el \n\n.

Naturalmente, esta salida la obtienes a través del intérprete interactivo. Si quieres ver el resultado en un programa tendrás que usar la función print() para mostrarla.

>>> fichero.seek(0)
0
>>> print(fichero.read())
Comienza el fichero con una mención a la casa de la pradera.
La segunda línea suele hallarse después de la primera.

Esta es la cuarta línea, en la tercera había una línea en blanco.
Es una verdadera lástima que esta sea la última línea.

Una lectura con read(), al igual que la iteración, deja exhausto el fichero, posicionando el cursor de lectura al final de todo:

>>> fichero.read()
''

Presta mucha atención a esto: la cadena vacía ” es el indicativo que tiene Python para detectar que ha llegado al final del archivo, hecho que podremos utilizar en nuestro código a la hora de hacer lecturas.

Otro método que debes conocer es readline() que, a diferencia del anterior, que realiza una lectura completa, recupera cada línea de una en una:

>>> fichero.seek(0)
0
>>> fichero.readline()
'Comienza el fichero con una mención a la casa de la pradera.\n'

Como el cursor estará posicionado al comienzo de la línea siguiente, cada nueva ejecución de readline() nos recuperará la línea adecuada:

>>> fichero.readline()
'La segunda línea suele hallarse después de la primera.\n'
>>> fichero.readline()
'\n'
>>> fichero.readline()
'Esta es la cuarta línea, en la tercera había una línea en blanco.\n'
>>> fichero.readline()
'Es una verdadera lástima que esta sea la última línea.\n'
>>> fichero.readline()
''

Observa nuevamente la cadena vacía para indicar que ya hemos alcanzado el final del archivo.

A continuación, uno de mis metodos favoritos: readlines(), como el anterior, pero esta vez en plural.

Este método devuelve una lista en la que cada elemento es una línea del fichero:

>>> fichero.seek(0)
0
>>> fichero.readlines()
['Comienza el fichero con una mención a la casa de la pradera.\n', 
'La segunda línea suele hallarse después de la primera.\n', 
'\n', 
'Esta es la cuarta línea, en la tercera había una línea en blanco.\n', 
'Es una verdadera lástima que esta sea la última línea.\n']

Asocia su salida a una variable y en una única lectura tendrás una lista que podrás manipular tranquilamente a tus anchas sin preocuparte de cursores.

Para finalizar, una vez hemos terminado de usar el objeto fichero, debemos proceder a cerrarlo, liberando así la memoria que estaba consumiendo y rompiendo el vínculo con el fichero real.

>>> fichero.close()

A partir de ahí, nuestra abstracción fichero dejará de estar disponible. Si necesitaras volver a hacer uso del archivo deberías abrirlo nuevamente.

Suficiente por hoy. No olvides las tres erres: read, readline y readlines.

Javier Montero Gabarró


Python: Aprendiendo a leer


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.