Escritura en archivos
Siguiendo con la lógica de la [entrada anterior], una vez creado (y abierto) el archivo deberemos proceder trasladar a él los datos generados por nuestro script, procedimiento llamado escritura (1). Dedicaremos esta entrada a explicar las diferentes formas que tenemos de escribir en un archivo txt desde un script de Python.
Como sabemos, de las instrucciones que usamos como concreción del segundo parámetro de la función open(), tres nos permiten escribir (2) en el archivo: x, w y a.
Cada una de ellas tiene un comportamiento particular, tanto respecto a la existencia previo (o no) del archivo, como al modo de trabajar con él.
- La opción x (create) parece, en principio, ser la más apropiada, pero tiene un inconveniente: si el archivo que pretendemos crear ya existe, devuelve error, por lo que es necesario asegurar que dicho archivo no exista (3).
- La opción w crea el archivo si éste no existe y no devuelve error, pero borrar lo que contenga y sitúa el cursor al inicio del archivo.
- Por último, la opción a funciona igual que la anterior y tiene la ventaja de no alterar el contenido previo del archivo en caso de que éste exista, situando el cursor al final del archivo.
Sabiendo lo anterior podemos optar por la opción que mejor se ajuste a nuestras necesidades (4). Por ejemplo:
- Si la prioridad es crear un nuevo archivo conociendo a ciencia cierta que no existe, cualquiera de las tres opciones es válida. x parece la más específica, pero en realidad las tres tienen, en este caso, el mismo comportamiento, ya que la posición del cursor dentro del archivo (posición de partida para escribir en él) siempre será el inicio del mismo (5).
- Si lo que deseamos es continuar escribiendo en un archivo ya creado, la mejor opción es a, ya que nos garantiza que se respeta el contenido previo y que el nuevo se escribe a continuación.
- Si nuestro cometido es mantener actualizado y sin redundancias un determinado archivo, la mejor opción es w, ya que nos garantiza que no se producirá error (como en el caso de x) si el archivo ya existe, y que siempre estará actualizado.
Vamos a explicar a continuación el proceso mismo de escritura, empezando por la la función write() en su uso más simple. Un ejemplo...
archivo = open('texto1.txt','x', encoding='utf-8')
archivo.write('Pedro como plátanos')
... una variación sobre el mismo tema, sustituyendo la cadena por la variable que la referencia...
frase ='Pedro come plátanos'
archivo = open('texto1.txt','x', encoding='utf-8')
... y una tercera formulación, más sofisticada e interactiva, pero en lo principal, la misma:
nombre = input('Dime el nombre de la persona: ')
verbo = input(f'¿Qué hace {nombre }? ')
objeto = input(f'¿Qué {verbo} {nombre} ')
frase = (f'{nombre} {verbo} {objeto}') #Concetana el contenido de las tres variables
archivo = open('texto1.txt','x', encoding='utf-8')
También podemos trabajar con colecciones de datos y con bucles, previamente a la escritura del contenido en el archivo y en proceso de escritura.
Pensemos, por ejemplo, en una lista de vocabulario básico que almacenamos inicialmente en una lista y que después escribimos en un archivo.
archivo = open('texto1.txt','x', encoding='utf-8')
Aunque este script nos permite crear, acceder y escribir en el archivo (texto1.txt), el problema que nos encontramos (al acceder al acceder al archivo) es el siguiente: PeraPlátanoManzanaNaranjaFresa. Todas las palabras se escribieron juntas, en una misma línea. Es posible que queramos que se escriban en una única línea, una detrás de otra (a modo de lista), pero lo que es seguro es que no nos interesa que aparezcan en un sólo bloque, como una única palabras. Incluso es posible que deseemos que cada una de ellas se escriba en una línea diferentes. Vamos a ver cómo lo podemos solucionar.
- Por ejemplo, si usamos la siguiente instrucción (archivo.write(' ')) tras (archivo.write(fruta)) obtendremos Pera Plátano Manzana Naranja Fresa. La razón: tras cada elemento de la lista escribimos un espacio mediante esa nueva instrucción.
- Siguiendo este procedimiento, y manteniendo la escritura del listado en una misma línea, podemos añadir cualquier carácter o grupo de caracteres para separar cada elemento de la lista, como, por ejemplo sustituyendo (archivo.write(' ')) por (archivo.write('||')), con lo que obtendremos Pera||Plátano||Manzana||Naranja||Fresa||.
- Y estarás pensando que si usas el carácter salto de línea es posible escribir la lista en diferentes líneas (archivo.write('\n')). Y estarás en lo cierto.
Pues bien, el mismo efecto que obtenemos con el uso del bucle (for fruta in frutas:) lo obtenemos usando la función join() como te muestro en el siguiente script (6)
archivo = open('texto1.txt','x', encoding='utf-8')
texto = '\n'.join(frutas) #Si no queremos saltos de línea podemos usar, por ejemplo '||'
archivo.write(texto)
archivo.close()
... con el que conseguimos el mismo efecto que con la anterior formulación del script con bucle (7).
Cuando el texto a guardar es de varias líneas, podemos usar el método writelines() en sustitución de writer(). También este método nos ahorra el uso del bucle, ya que escribe las múltiples líneas de las que puede estar compuesto un texto o los diferentes elementos de una lista...
archivo = open('texto1.txt','x', encoding='utf-8')
archivo.writelines(frutas)
... pero tiene un problema: o modificamos la lista introduciendo "separadores" entre su elementos, o lo que se escribe es una única "palabra" (PeraPlátanoManzanaNaranjaFresa) (8)
Y ya puestos a ahorrar, si queremos prescindir de la función close() (archivo.close()) podemos recurrir with (9), como, por ejemplo...
frutas = ["Manzana\n", "Pera\n", "Plátano\n"]
with open("texto1.txt", 'w', encoding='utf-8') as archivo:
archivo.writelines(frutas)
... cuyas sentencias subordinadas (en este caso archivo.writelines(frutas)) podemos formular de formas similares a como hicimos en los ejemplos anteriores (10)
NOTAS
(1) Por oposición al de recuperación del contenido del archivo o de lectura.
(2) Crear, si no está creado, y escribir en el archivo. x da error si el archivo ya existe, cosa que no sucede ni con a ni con w. La diferencia entre ambos se explica en el texto de la entrada.
(3) La función isfile() nos puede ayudar, ya que devuelve un valor booleano (True/False) que controla la posible existencia del archivo.
(4) Si mantenemos la lógica de lo que estamos haciendo (escribir sobre un archivo recién creado), cualquiera de las tres opciones nos vale, aunque en sentido estricto deberíamos usar x.
(5) Es posible que esta sea la causa de que en algunos manuales no se haga mención de la opción x, entendiéndola redundante en caso de inexistencia del archivo y potencialmente negativa en caso de duda al respecto. Esta es una observación personal no contrastada, por lo que ha de tomarse con reservas. Dada la importancia que tiene en el proceso de escritura (y lectura) conocer la posición que ocupa el cursor interno, Python dispone de funciones específicas para este fin. Estas opciones no van a ser tratadas en esta entrada, ya que tiene carácter introductorio, pero las explicaré cuando el objetivo de aprendizaje (y uso práctico) lo haga necesario.
(6) Observa que en este nuevo script han cambiado algunas cosas más que el bucle.
(7) Y si sustituimos '\n' por cualquier combinación de caracteres (vg texto = '||'.join(frutas) ) obtendremos resultados similares a las otras formulaciones de script: todos los elementos en la misma línea, separados por esos caracteres (vg, de nuevo Pera||Plátano||Manzana||Naranja||Fresa||)
(8) Una posible solución es escribiendo la lista como sigue: frutas=['Pera', '\n','Plátano','\n', 'Manzana','\n','Naranja','\n','Fresa']. En estos casos personalmente prefiero usar el bucle o la función join().
(9) Que realmente ahorra más que la instrucción archivo.close(), como se puede comprobar en la entrada.
(10) Aquí buscamos la forma extrema de simplificación del código que permite el uso de with para que se aprecie mejor el efecto indicado en 9. Puede que no sea el que mejor se acomode a tus necesidades.