Versuchen Sie es fileinputwie von @ jf-sebastian hier beschrieben . Es scheint Ihnen zu ermöglichen, Zeile für Zeile über eine temporäre Datei mit einer einfachen forSyntax zu arbeiten.
Kevin
Antworten:
205
Öffnen Sie zuerst die Datei und holen Sie alle Ihre Zeilen aus der Datei. Öffnen Sie dann die Datei im Schreibmodus erneut und schreiben Sie Ihre Zeilen zurück, mit Ausnahme der Zeile, die Sie löschen möchten:
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)
Sie müssen strip("\n")das Newline-Zeichen im Vergleich verwenden, denn wenn Ihre Datei nicht mit einem Newline-Zeichen endet, wird das allerletzte lineauch nicht.
@Ooker: Sie müssen die Datei zweimal öffnen (und dazwischen schließen), da sie im ersten Modus "schreibgeschützt" ist, weil Sie nur die aktuellen Zeilen in der Datei lesen. Sie schließen es dann und öffnen es erneut im "Schreibmodus", in dem die Datei beschreibbar ist, und Sie ersetzen den Inhalt der Datei ohne die Zeile, die Sie entfernen möchten.
Devin
4
Warum erlaubt uns Python nicht, dies in einer Zeile zu tun?
Ooker
5
@Ooker, Wenn Sie eine Zeile lesen, stellen Sie sich einen Cursor vor, der sich beim Lesen entlang der Zeile bewegt. Sobald diese Zeile gelesen wurde, ist der Cursor nun darüber hinaus. Wenn Sie versuchen, in die Datei zu schreiben, schreiben Sie, wo sich der Cursor gerade befindet. Durch erneutes Öffnen der Datei setzen Sie den Cursor zurück.
Waddas
4
Verwenden Sie die mit Verbindung!
Sceluswe
100
Lösung für dieses Problem mit nur einem einzigen offenen:
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()
Diese Lösung öffnet die Datei im R / W-Modus ("r +") und verwendet die Suche, um den f-Zeiger zurückzusetzen und dann abzuschneiden, um alles nach dem letzten Schreibvorgang zu entfernen.
Dies funktionierte sehr gut für mich, da ich auch lockfile (fcntl) verwenden musste. Ich konnte keine Möglichkeit finden, fileinput zusammen mit fcntl zu verwenden.
Easyrider
1
Es wäre schön, einige Nebenwirkungen dieser Lösung zu sehen.
user1767754
3
Ich würde das nicht tun. Wenn Sie einen Fehler in der forSchleife erhalten, erhalten Sie eine teilweise überschriebene Datei mit doppelten Zeilen oder einer halb abgeschnittenen Zeile. Vielleicht möchten Sie stattdessen f.truncate()gleich danach f.seek(0). Auf diese Weise erhalten Sie bei einer Fehlermeldung nur eine unvollständige Datei. Die eigentliche Lösung (wenn Sie über ausreichend Speicherplatz verfügen) besteht darin, in eine temporäre Datei auszugeben und diese dann zu verwenden os.replace()oder pathlib.Path(temp_filename).replace(original_filename)mit dem Original auszutauschen, nachdem alles erfolgreich war.
Boris
Könnten Sie hinzufügen, i.strip('\n') != "line you want to remove..."wie in der akzeptierten Antwort erwähnt, das würde mein Problem perfekt lösen. Weil iich einfach nichts für mich getan habe
Mangohero1
31
Die beste und schnellste Option, anstatt alles in einer Liste zu speichern und die Datei erneut zu öffnen, um sie zu schreiben, ist meiner Meinung nach, die Datei an anderer Stelle neu zu schreiben.
with open("yourfile.txt","r")as input:with open("newfile.txt","w")as output:for line in input:if line.strip("\n")!="nickname_to_delete":
output.write(line)
Das ist es! In einer Schleife und nur einer können Sie dasselbe tun. Es wird viel schneller sein.
Anstatt die normale for-Schleife zu verwenden, können wir den Generatorausdruck verwenden. Auf diese Weise lädt das Programm nicht alle Zeilen von der Datei in den Speicher, was bei großen Dateien keine gute Idee ist. Es wird jeweils nur eine Zeile gespeichert. Mit Generator Ausdruck für Schleife wird aussehen,(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
shrishinde
4
@ShriShinde Sie lesen die Datei auch nicht in den Speicher, wenn Sie das Dateiobjekt durchlaufen, daher funktioniert diese Lösung identisch mit Ihrem Vorschlag.
Steinar Lima
Vielleicht möchten Sie die Originaldatei löschen und die zweite Datei in den Namen der Originaldatei umbenennen, was mit Python unter einem Linux-Betriebssystem so aussehen würdesubprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
Max
6
os.replace(neu in Python v 3.3) ist plattformübergreifender als ein Systemaufruf mv.
7yl4r
Einfach und großartig.
JuBaer AD
27
Dies ist eine "Abzweigung" aus der Antwort von @Lother (die meiner Meinung nach als die richtige Antwort angesehen werden sollte).
Für eine Datei wie diese:
$ cat file.txt
1: october rust
2: november rain
3: december snow
Diese Gabel aus Lothers Lösung funktioniert einwandfrei:
#!/usr/bin/python3.4with open("file.txt","r+")as f:
new_f = f.readlines()
f.seek(0)for line in new_f:if"snow"notin line:
f.write(line)
f.truncate()
Verbesserungen:
with open, die die Verwendung von verwerfen f.close()
Klarer if/elsefür die Bewertung, ob die Zeichenfolge in der aktuellen Zeile nicht vorhanden ist
@ Yifan ja. Andernfalls hängen Sie die Datei an sich selbst an, anstatt sie zu überschreiben (ohne die Zeilen, die Sie ausschließen).
Boris
5
Das Problem beim Lesen von Zeilen im ersten Durchgang und beim Vornehmen von Änderungen (Löschen bestimmter Zeilen) im zweiten Durchgang besteht darin, dass Ihnen bei großen Dateigrößen der Arbeitsspeicher ausgeht. Stattdessen ist es besser, die Zeilen einzeln zu lesen und in eine separate Datei zu schreiben, um die nicht benötigten zu entfernen. Ich habe diesen Ansatz mit Dateien mit einer Größe von 12 bis 50 GB ausgeführt, und die RAM-Auslastung bleibt nahezu konstant. Nur CPU-Zyklen zeigen die laufende Verarbeitung an.
Diese Lösung ist nicht betriebssystemunabhängig, und da OP kein Betriebssystem angegeben hat, gibt es keinen Grund, eine Linux-spezifische Antwort imo zu veröffentlichen.
Steinar Lima
2
Jeder, der vorschlägt, einen Unterprozess für alles zu verwenden, was nur mit Python möglich ist, erhält eine Abwertung! Und +1 an @SteinarLima ... Ich stimme zu
Jamie Lindsey
2
Ich denke, wenn Sie die Datei in eine Liste einlesen, können Sie die Liste durchlaufen, um nach dem Spitznamen zu suchen, den Sie entfernen möchten. Sie können dies sehr effizient tun, ohne zusätzliche Dateien zu erstellen, aber Sie müssen das Ergebnis in die Quelldatei zurückschreiben.
So könnte ich das machen:
import, os, csv # and other imports you need
nicknames_to_delete =['Nick','Stephen','Mark']
Ich gehe davon aus, nicknames.csventhält Daten wie:
Als nächstes iterieren Sie zur Liste, um Ihren zu löschenden Eingaben zu entsprechen:
for nick in nicknames_to_delete:try:if nick in nicknames:
nicknames.pop(nicknames.index(nick))else:print(nick +" is not found in the file")exceptValueError:pass
Zuletzt schreiben Sie das Ergebnis zurück in die Datei:
with open("nicknames.csv","a")as nicknamesFile:
nicknamesFile.seek(0)
nicknamesFile.truncate()
nicknamesWriter = csv.writer(nicknamesFile)for name in nicknames:
nicknamesWriter.writeRow([str(name)])
nicknamesFile.close()
Im Allgemeinen können Sie nicht; Sie müssen die gesamte Datei erneut schreiben (zumindest vom Zeitpunkt der Änderung bis zum Ende).
In bestimmten Fällen können Sie es besser machen -
Wenn alle Ihre Datenelemente dieselbe Länge und keine bestimmte Reihenfolge haben und Sie den Versatz des Elements kennen, das Sie entfernen möchten, können Sie das letzte Element über das zu löschende Element kopieren und die Datei vor dem letzten Element abschneiden ;;
Oder Sie können den Datenblock einfach mit dem Wert "Dies sind fehlerhafte Daten, überspringen Sie ihn" überschreiben oder das Flag "Dieses Element wurde gelöscht" in Ihren gespeicherten Datenelementen beibehalten, sodass Sie es als gelöscht markieren können, ohne die Datei anderweitig zu ändern.
Dies ist wahrscheinlich ein Overkill für kurze Dokumente (alles unter 100 KB?).
Wahrscheinlich haben Sie bereits eine richtige Antwort erhalten, aber hier ist meine. Anstatt eine Liste zum Sammeln ungefilterter Daten zu verwenden (welche readlines()Methode funktioniert), verwende ich zwei Dateien. Eine dient zum Halten von Hauptdaten und die zweite zum Filtern der Daten, wenn Sie eine bestimmte Zeichenfolge löschen. Hier ist ein Code:
main_file = open('data_base.txt').read()# your main dataBase file
filter_file = open('filter_base.txt','w')
filter_file.write(main_file)
filter_file.close()
main_file = open('data_base.txt','w')for line in open('filter_base'):if'your data to delete'notin line:# remove a specific string
main_file.write(line)# put all strings back to your db except deletedelse:pass
main_file.close()
Speichern Sie die Dateizeilen in einer Liste, entfernen Sie dann die zu löschende Zeile aus der Liste und schreiben Sie die verbleibenden Zeilen in eine neue Datei
with open("file_name.txt","r")as f:
lines = f.readlines()
lines.remove("Line you want to delete\n")with open("new_file.txt","w")as new_f:for line in lines:
new_f.write(line)
Wenn Ihre Datei nicht mit einer neuen Zeile endet, entfernt dieser Code die letzte Zeile nicht, selbst wenn er ein Wort enthält, das Sie entfernen möchten.
Boris
0
Hier ist eine andere Methode, um eine / mehrere Zeile (n) aus einer Datei zu entfernen:
src_file = zzzz.txt
f = open(src_file,"r")
contents = f.readlines()
f.close()
contents.pop(idx)# remove the line item from list, by line number, starts from 0
f = open(src_file,"w")
contents ="".join(contents)
f.write(contents)
f.close()
Angenommen, Sie können Ihre vollständige txt-Datei laden. Anschließend definieren Sie eine Liste unerwünschter Spitznamen und ersetzen diese durch eine leere Zeichenfolge "".
# Delete unwanted charactersimport re
# Read, then decode for py2 compat.
path_to_file ='data/nicknames.txt'
text = open(path_to_file,'rb').read().decode(encoding='utf-8')# Define unwanted nicknames and substitute them
unwanted_nickname_list =['SourDough']
text = re.sub("|".join(unwanted_nickname_list),"", text)
Es ist nicht nötig, ein Diktat zu erstellen. Verwenden Sie einfachfor nb, line in enumerate(f.readlines())
Dionys
-3
Nehmen Sie den Inhalt der Datei und teilen Sie ihn durch Zeilenumbruch in ein Tupel auf. Greifen Sie dann auf die Zeilennummer Ihres Tupels zu, verbinden Sie Ihr Ergebnistupel und überschreiben Sie die Datei.
(1) meinst du tuple(f.read().split('\n'))? (2) "Zugriff auf die Zeilennummer Ihres Tupels" und "Join your result tuple" klingen ziemlich mysteriös; Der tatsächliche Python-Code ist möglicherweise verständlicher.
fileinput
wie von @ jf-sebastian hier beschrieben . Es scheint Ihnen zu ermöglichen, Zeile für Zeile über eine temporäre Datei mit einer einfachenfor
Syntax zu arbeiten.Antworten:
Öffnen Sie zuerst die Datei und holen Sie alle Ihre Zeilen aus der Datei. Öffnen Sie dann die Datei im Schreibmodus erneut und schreiben Sie Ihre Zeilen zurück, mit Ausnahme der Zeile, die Sie löschen möchten:
Sie müssen
strip("\n")
das Newline-Zeichen im Vergleich verwenden, denn wenn Ihre Datei nicht mit einem Newline-Zeichen endet, wird das allerletzteline
auch nicht.quelle
Lösung für dieses Problem mit nur einem einzigen offenen:
Diese Lösung öffnet die Datei im R / W-Modus ("r +") und verwendet die Suche, um den f-Zeiger zurückzusetzen und dann abzuschneiden, um alles nach dem letzten Schreibvorgang zu entfernen.
quelle
for
Schleife erhalten, erhalten Sie eine teilweise überschriebene Datei mit doppelten Zeilen oder einer halb abgeschnittenen Zeile. Vielleicht möchten Sie stattdessenf.truncate()
gleich danachf.seek(0)
. Auf diese Weise erhalten Sie bei einer Fehlermeldung nur eine unvollständige Datei. Die eigentliche Lösung (wenn Sie über ausreichend Speicherplatz verfügen) besteht darin, in eine temporäre Datei auszugeben und diese dann zu verwendenos.replace()
oderpathlib.Path(temp_filename).replace(original_filename)
mit dem Original auszutauschen, nachdem alles erfolgreich war.i.strip('\n') != "line you want to remove..."
wie in der akzeptierten Antwort erwähnt, das würde mein Problem perfekt lösen. Weili
ich einfach nichts für mich getan habeDie beste und schnellste Option, anstatt alles in einer Liste zu speichern und die Datei erneut zu öffnen, um sie zu schreiben, ist meiner Meinung nach, die Datei an anderer Stelle neu zu schreiben.
Das ist es! In einer Schleife und nur einer können Sie dasselbe tun. Es wird viel schneller sein.
quelle
(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
os.replace
(neu in Python v 3.3) ist plattformübergreifender als ein Systemaufrufmv
.Dies ist eine "Abzweigung" aus der Antwort von @Lother (die meiner Meinung nach als die richtige Antwort angesehen werden sollte).
Für eine Datei wie diese:
Diese Gabel aus Lothers Lösung funktioniert einwandfrei:
Verbesserungen:
with open
, die die Verwendung von verwerfenf.close()
if/else
für die Bewertung, ob die Zeichenfolge in der aktuellen Zeile nicht vorhanden istquelle
Das Problem beim Lesen von Zeilen im ersten Durchgang und beim Vornehmen von Änderungen (Löschen bestimmter Zeilen) im zweiten Durchgang besteht darin, dass Ihnen bei großen Dateigrößen der Arbeitsspeicher ausgeht. Stattdessen ist es besser, die Zeilen einzeln zu lesen und in eine separate Datei zu schreiben, um die nicht benötigten zu entfernen. Ich habe diesen Ansatz mit Dateien mit einer Größe von 12 bis 50 GB ausgeführt, und die RAM-Auslastung bleibt nahezu konstant. Nur CPU-Zyklen zeigen die laufende Verarbeitung an.
quelle
Ich mochte den Dateieingabeansatz, wie in dieser Antwort erläutert: Löschen einer Zeile aus einer Textdatei (Python)
Angenommen, ich habe eine Datei mit leeren Zeilen und möchte leere Zeilen entfernen. So habe ich sie gelöst:
quelle
Wenn Sie Linux verwenden, können Sie den folgenden Ansatz ausprobieren.
Angenommen, Sie haben eine Textdatei mit dem Namen
animal.txt
:Löschen Sie die erste Zeile:
dann
quelle
Ich denke, wenn Sie die Datei in eine Liste einlesen, können Sie die Liste durchlaufen, um nach dem Spitznamen zu suchen, den Sie entfernen möchten. Sie können dies sehr effizient tun, ohne zusätzliche Dateien zu erstellen, aber Sie müssen das Ergebnis in die Quelldatei zurückschreiben.
So könnte ich das machen:
Ich gehe davon aus,
nicknames.csv
enthält Daten wie:Laden Sie dann die Datei in die Liste:
Als nächstes iterieren Sie zur Liste, um Ihren zu löschenden Eingaben zu entsprechen:
Zuletzt schreiben Sie das Ergebnis zurück in die Datei:
quelle
Im Allgemeinen können Sie nicht; Sie müssen die gesamte Datei erneut schreiben (zumindest vom Zeitpunkt der Änderung bis zum Ende).
In bestimmten Fällen können Sie es besser machen -
Wenn alle Ihre Datenelemente dieselbe Länge und keine bestimmte Reihenfolge haben und Sie den Versatz des Elements kennen, das Sie entfernen möchten, können Sie das letzte Element über das zu löschende Element kopieren und die Datei vor dem letzten Element abschneiden ;;
Oder Sie können den Datenblock einfach mit dem Wert "Dies sind fehlerhafte Daten, überspringen Sie ihn" überschreiben oder das Flag "Dieses Element wurde gelöscht" in Ihren gespeicherten Datenelementen beibehalten, sodass Sie es als gelöscht markieren können, ohne die Datei anderweitig zu ändern.
Dies ist wahrscheinlich ein Overkill für kurze Dokumente (alles unter 100 KB?).
quelle
Wahrscheinlich haben Sie bereits eine richtige Antwort erhalten, aber hier ist meine. Anstatt eine Liste zum Sammeln ungefilterter Daten zu verwenden (welche
readlines()
Methode funktioniert), verwende ich zwei Dateien. Eine dient zum Halten von Hauptdaten und die zweite zum Filtern der Daten, wenn Sie eine bestimmte Zeichenfolge löschen. Hier ist ein Code:Ich hoffe, Sie finden das nützlich! :) :)
quelle
Speichern Sie die Dateizeilen in einer Liste, entfernen Sie dann die zu löschende Zeile aus der Liste und schreiben Sie die verbleibenden Zeilen in eine neue Datei
quelle
Hier ist eine andere Methode, um eine / mehrere Zeile (n) aus einer Datei zu entfernen:
quelle
Ich mag diese Methode mit fileinput und der 'inplace'-Methode:
Es ist etwas weniger wortreich als die anderen Antworten und schnell genug dafür
quelle
Angenommen, Sie können Ihre vollständige txt-Datei laden. Anschließend definieren Sie eine Liste unerwünschter Spitznamen und ersetzen diese durch eine leere Zeichenfolge "".
quelle
So löschen Sie eine bestimmte Zeile einer Datei anhand ihrer Zeilennummer :
Ersetzen Sie die Variablen Dateiname und line_to_delete durch den Namen Ihrer Datei und die Zeilennummer, die Sie löschen möchten.
Beispiel Ausgabe :
quelle
for nb, line in enumerate(f.readlines())
Nehmen Sie den Inhalt der Datei und teilen Sie ihn durch Zeilenumbruch in ein Tupel auf. Greifen Sie dann auf die Zeilennummer Ihres Tupels zu, verbinden Sie Ihr Ergebnistupel und überschreiben Sie die Datei.
quelle
tuple(f.read().split('\n'))
? (2) "Zugriff auf die Zeilennummer Ihres Tupels" und "Join your result tuple" klingen ziemlich mysteriös; Der tatsächliche Python-Code ist möglicherweise verständlicher.