amargo
Digamos que tengo un archivo de texto lleno de apodos. ¿Cómo puedo eliminar un apodo específico de este archivo usando Python?
houbysoft
Primero, abra el archivo y obtenga todas sus líneas del archivo. Luego vuelva a abrir el archivo en modo de escritura y vuelva a escribir sus líneas, excepto la línea que desea eliminar:
with open("yourfile.txt", "r") as f:
lines = f.readlines()
with open("yourfile.txt", "w") as f:
for line in lines:
if line.strip("\n") != "nickname_to_delete":
f.write(line)
Necesitas strip("\n")
el carácter de nueva línea en la comparación porque si su archivo no termina con un carácter de nueva línea, el último line
tampoco.
-
¿Por qué tenemos que abrirlo y cerrarlo dos veces?
– Oker
25 de junio de 2014 a las 13:48
-
@Ooker: debe abrir el archivo dos veces (y cerrarlo en el medio) porque en el primer modo es “solo lectura” porque solo está leyendo las líneas actuales en el archivo. Luego lo cierra y lo vuelve a abrir en “modo de escritura”, donde se puede escribir en el archivo y reemplaza el contenido del archivo sin la línea que desea eliminar.
– Devin
1 de julio de 2014 a las 16:19
-
¿Por qué Python no nos permite hacer esto en una sola línea?
– Oker
1 de julio de 2014 a las 16:37
-
@Ooker, cuando lea una línea, intente imaginar un cursor moviéndose a lo largo de la línea mientras se lee. Una vez que se ha leído esa línea, el cursor ya la ha pasado. Cuando intenta escribir en el archivo, escribe donde se encuentra actualmente el cursor. Al volver a abrir el archivo, reinicia el cursor.
– Waddas
06/08/2014 a las 20:48
-
Esta tarea se puede realizar abriendo el archivo solo una vez… pero debe abrirse ‘r+’, Y, debe llamar a flie.seek(0) (para mover el cursor al principio) y file.truncate () (para invalidar los contenidos existentes), antes de proceder a reescribirlo.
– Josué Clayton
25 de enero de 2019 a las 23:10
Lother
Solución a este problema con una sola apertura:
with open("target.txt", "r+") as f:
d = f.readlines()
f.seek(0)
for i in d:
if i != "line you want to remove...":
f.write(i)
f.truncate()
Esta solución abre el archivo en modo r/w (“r+”) y utiliza la búsqueda para restablecer el puntero f y luego truncar para eliminar todo después de la última escritura.
-
Esto funcionó muy bien para mí, ya que también tuve que usar lockfile (fcntl). No pude encontrar ninguna forma de usar fileinput junto con fcntl.
– Jinete facil
27 de enero de 2015 a las 14:07
-
Sería bueno ver algunos efectos secundarios de esta solución.
– usuario1767754
23 de noviembre de 2017 a las 8:43
-
Yo no haría esto. Si obtiene un error en el
for
loop, terminará con un archivo parcialmente sobrescrito, con líneas duplicadas o una línea medio cortada. Tu podrías quererf.truncate()
justo después def.seek(0)
en cambio. De esa manera, si obtiene un error, terminará con un archivo incompleto. Pero la solución real (si tiene espacio en disco) es generar un archivo temporal y luego usaros.replace()
opathlib.Path(temp_filename).replace(original_filename)
para intercambiarlo con el original después de que todo haya tenido éxito.– Boris Verjovskiy
22 de marzo de 2019 a las 13:48
-
podrías agregar
i.strip('\n') != "line you want to remove..."
como se menciona en la respuesta aceptada, eso resolvería perfectamente mi problema. porque soloi
no hizo nada por mi– Mangohero1
6 de abril de 2020 a las 2:47
Bernabé
En mi opinión, la mejor y más rápida opción, en lugar de almacenar todo en una lista y volver a abrir el archivo para escribirlo, es volver a escribir el archivo en otro lugar.
with open("yourfile.txt", "r") as file_input:
with open("newfile.txt", "w") as output:
for line in file_input:
if line.strip("\n") != "nickname_to_delete":
output.write(line)
¡Eso es todo! En un bucle y solo uno puedes hacer lo mismo. Será mucho más rápido.
-
En lugar de usar el bucle for normal, podemos hacer uso de Expresión del generador De esta manera, el programa no cargará todas las líneas del archivo a la memoria, lo que no es una buena idea en el caso de archivos grandes. Solo tendrá una sola línea en la memoria a la vez. Con la expresión del generador, el bucle se verá así,
(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
– Shrishinde
25 de febrero de 2016 a las 7:41
-
@ShriShinde Tampoco está leyendo el archivo en la memoria cuando recorre el objeto del archivo, por lo que esta solución funciona de manera idéntica a su sugerencia.
– Steinar Lima
27 de febrero de 2016 a las 7:18
-
Es posible que desee eliminar el archivo original y cambiar el nombre del segundo archivo al nombre del archivo original, que con Python en un sistema operativo Linux se vería así:
subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
– Máx.
28 de noviembre de 2016 a las 0:15
-
os.replace
(nuevo en python v 3.3) es más multiplataforma que una llamada al sistema paramv
.– 7yl4r
15/11/2017 a las 15:30
-
Creo que esta es una mejor solución porque no almacena todo el archivo en la memoria antes de realizar cambios, lo que podría ser un problema con archivos muy grandes.
– ecv
24 de marzo a las 9:18
ivanleoncz
Este es un “tenedor” de @LotherLa respuesta de (debe considerarse la respuesta correcta).
Para un archivo como este:
$ cat file.txt
1: october rust
2: november rain
3: december snow
Este código:
#!/usr/bin/python3.4
with open("file.txt","r+") as f:
new_f = f.readlines()
f.seek(0)
for line in new_f:
if "snow" not in line:
f.write(line)
f.truncate()
Mejoras:
with open
que descarta el uso def.close()
- mas claro
if/else
para evaluar si la cadena no está presente en la línea actual
El problema con la lectura de líneas en la primera pasada y la realización de cambios (eliminación de líneas específicas) en la segunda pasada es que si el tamaño de los archivos es enorme, se quedará sin RAM. En cambio, un mejor enfoque es leer líneas, una por una, y escribirlas en un archivo separado, eliminando las que no necesita. He ejecutado este enfoque con archivos de hasta 12-50 GB y el uso de RAM permanece casi constante. Solo los ciclos de CPU muestran el procesamiento en curso.
Profundo
Me gustó el enfoque de entrada de archivos como se explica en esta respuesta: Eliminar una línea de un archivo de texto (python)
Digamos, por ejemplo, que tengo un archivo que tiene líneas vacías y quiero eliminar las líneas vacías, así es como lo resolví:
import fileinput
import sys
for line_number, line in enumerate(fileinput.input('file1.txt', inplace=1)):
if len(line) > 1:
sys.stdout.write(line)
Nota: Las líneas vacías en mi caso tenían una longitud de 1
Si usa Linux, puede probar el siguiente enfoque.
Supongamos que tiene un archivo de texto llamado animal.txt
:
$ cat animal.txt
dog
pig
cat
monkey
elephant
Eliminar la primera línea:
>>> import subprocess
>>> subprocess.call(['sed','-i','/.*dog.*/d','animal.txt'])
entonces
$ cat animal.txt
pig
cat
monkey
elephant
-
Esta solución no es independiente del sistema operativo, y dado que OP no especificó un sistema operativo, no hay razón para publicar una respuesta específica de Linux.
– Steinar Lima
27 de febrero de 2016 a las 7:20
-
¡Cualquiera que sugiera usar el subproceso para cualquier cosa que se pueda hacer solo con python recibe un voto negativo! Y +1 a @SteinarLima… Estoy de acuerdo
– Jamie Lindsey
25 de diciembre de 2018 a las 1:40
-
El
-i
La opción no es estándar y funciona de manera diferente en plataformas *BSD (incluido macOS) que en Linux. de pitónfileinput
El módulo hace lo mismo de forma transparente, portátil y nativa.– triplete
3 abr 2021 a las 9:51
Intentar
fileinput
como lo describe @jf-sebastian aquí. Parece permitirle trabajar línea por línea, a través de un archivo temporal, todo con un simplefor
sintaxis.–Kevin
21 de abril de 2016 a las 18:38