Gibt es Alternativen zum folgenden Code:
startFromLine = 141978 # or whatever line I need to jump to
urlsfile = open(filename, "rb", 0)
linesCounter = 1
for line in urlsfile:
if linesCounter > startFromLine:
DoSomethingWithThisLine(line)
linesCounter += 1
Wenn ich eine große Textdatei (~15MB)
mit Zeilen unbekannter, aber unterschiedlicher Länge verarbeite und zu einer bestimmten Zeile springen muss, welche Nummer kenne ich im Voraus? Ich fühle mich schlecht, wenn ich sie einzeln verarbeite, wenn ich weiß, dass ich mindestens die erste Hälfte der Datei ignorieren kann. Suchen Sie nach einer eleganteren Lösung, wenn es welche gibt.
python
text-files
user63503
quelle
quelle
Antworten:
Zeilencache :
quelle
Sie können nicht weitermachen, ohne die Datei mindestens einmal eingelesen zu haben, da Sie nicht wissen, wo sich die Zeilenumbrüche befinden. Sie könnten so etwas tun wie:
quelle
Sie haben nicht wirklich so viele Optionen, wenn die Zeilen unterschiedlich lang sind. Leider müssen Sie die Zeichen am Zeilenende verarbeiten, um zu wissen, wann Sie zur nächsten Zeile übergegangen sind.
Sie können dies jedoch drastisch beschleunigen UND die Speichernutzung reduzieren, indem Sie den letzten Parameter in "Öffnen" auf etwas ändern, das nicht 0 ist.
0 bedeutet, dass der Dateilesevorgang ungepuffert ist, was sehr langsam und festplattenintensiv ist. 1 bedeutet, dass die Datei zeilengepuffert ist, was eine Verbesserung wäre. Alles über 1 (z. B. 8 KB, dh 8096 oder höher) liest Teile der Datei in den Speicher. Sie greifen immer noch über zu
for line in open(etc):
, aber Python geht immer nur ein bisschen auf einmal und verwirft jeden gepufferten Block nach seiner Verarbeitung.quelle
Ich bin wahrscheinlich von reichlich Widder verwöhnt, aber 15 M sind nicht riesig.
readlines()
Mit Dateien dieser Größe lese ich normalerweise in den Speicher . Der Zugriff auf eine Leitung danach ist trivial.quelle
Ich bin überrascht, dass niemand Islice erwähnt hat
oder wenn Sie den gesamten Rest der Datei möchten
oder wenn Sie jede zweite Zeile aus der Datei möchten
quelle
Da es keine Möglichkeit gibt, die Länge aller Zeilen zu bestimmen, ohne sie zu lesen, haben Sie keine andere Wahl, als alle Zeilen vor Ihrer Startzeile zu durchlaufen. Alles, was Sie tun können, ist, es schön aussehen zu lassen. Wenn die Datei wirklich sehr groß ist, möchten Sie möglicherweise einen generatorbasierten Ansatz verwenden:
Hinweis: Der Index ist bei diesem Ansatz Null.
quelle
Wenn Sie nicht die gesamte Datei im Speicher lesen möchten, müssen Sie möglicherweise ein anderes Format als Nur-Text erstellen.
Natürlich hängt alles davon ab, was Sie versuchen und wie oft Sie über die Datei springen.
Wenn Sie beispielsweise mehrmals in derselben Datei zu Zeilen springen und wissen, dass sich die Datei während der Arbeit nicht ändert, können Sie Folgendes tun:
Gehen Sie zunächst die gesamte Datei durch und zeichnen Sie das " Suchort "einiger Schlüsselzeilennummern (z. B. je 1000 Zeilen).
Wenn Sie dann Zeile 12005 möchten, springen Sie zur Position 12000 (die Sie aufgezeichnet haben), lesen Sie dann 5 Zeilen und Sie werden Sie kennen Ich bin in der Linie 12005 und so weiter
quelle
Wenn Sie die Position in der Datei (statt der Zeilennummer) im Voraus kennen, können Sie mit file.seek () zu dieser Position wechseln .
Bearbeiten : Sie können die Funktion linecache.getline (Dateiname, Leinen) verwenden, die den Inhalt der Zeile Leinen zurückgibt, jedoch erst, nachdem die gesamte Datei in den Speicher gelesen wurde. Gut, wenn Sie zufällig auf Zeilen aus der Datei zugreifen (wie Python selbst möglicherweise einen Traceback drucken möchte), aber nicht gut für eine 15-MB-Datei.
quelle
Was generiert die Datei, die Sie verarbeiten möchten? Wenn Sie dies kontrollieren, können Sie zum Zeitpunkt des Anhängens der Datei einen Index erstellen (welche Zeile sich an welcher Position befindet). Die Indexdatei kann eine feste Zeilengröße haben (mit Leerzeichen oder 0 aufgefüllte Zahlen) und ist definitiv kleiner. Und kann so schnell gelesen und verarbeitet werden.
quelle
Ich hatte das gleiche Problem (muss aus einer großen dateispezifischen Zeile abgerufen werden).
Sicherlich kann ich jedes Mal alle Datensätze in der Datei durchgehen und stoppen, wenn der Zähler gleich der Zielzeile ist, aber es funktioniert nicht effektiv in einem Fall, in dem Sie mehrere bestimmte Zeilen erhalten möchten. Dies führte dazu, dass das Hauptproblem gelöst wurde - wie direkt zum erforderlichen Speicherort der Datei umgegangen werden kann.
Ich fand die nächste Entscheidung heraus: Zuerst vervollständigte ich das Wörterbuch mit der Startposition jeder Zeile (Schlüssel ist die Zeilennummer und die wertkumulierte Länge der vorherigen Zeilen).
letztendlich Zielfunktion:
t.seek (line_number) - Befehl, der das Bereinigen der Datei bis zum Zeilenbeginn ausführt. Wenn Sie also das nächste Mal eine Readline festschreiben, erhalten Sie Ihre Zielzeile.
Mit diesem Ansatz habe ich einen erheblichen Teil der Zeit gespart.
quelle
Sie können mmap verwenden, um den Versatz der Linien zu ermitteln. MMap scheint der schnellste Weg zu sein, eine Datei zu verarbeiten
Beispiel:
Verwenden Sie dann f.seek (Offsets), um zu der gewünschten Zeile zu gelangen
quelle
Enthalten die Zeilen selbst Indexinformationen? Wenn der Inhalt jeder Zeile so etwas wie "
<line index>:Data
" war,seek()
könnte der Ansatz verwendet werden, um eine binäre Suche in der Datei durchzuführen, selbst wenn die Menge vonData
variabel ist. Sie würden versuchen, den Mittelpunkt der Datei zu erreichen, eine Zeile lesen, prüfen, ob der Index höher oder niedriger als der gewünschte ist usw.Ansonsten ist das Beste, was Sie tun können, nur
readlines()
. Wenn Sie nicht alle 15 MB lesen möchten, können Sie dassizehint
Argument verwenden, um mindestens vielereadline()
s durch eine geringere Anzahl von Aufrufen zu zu ersetzenreadlines()
.quelle
Wenn Sie mit einer Textdatei arbeiten und auf einem Linux-System basieren , können Sie die Linux-Befehle verwenden.
Für mich hat das gut funktioniert!
quelle
Hier ist ein Beispiel mit 'readlines (sizehint)', um einen Teil der Zeilen gleichzeitig zu lesen. DNS wies auf diese Lösung hin. Ich habe dieses Beispiel geschrieben, weil die anderen Beispiele hier einzeilig sind.
quelle
Keine der Antworten ist besonders zufriedenstellend. Hier ist ein kleiner Ausschnitt, der Ihnen helfen soll.
Anwendungsbeispiel:
Dies beinhaltet viele Dateisuchen, ist jedoch nützlich für Fälle, in denen Sie nicht die gesamte Datei in den Speicher einpassen können. Es führt einen ersten Lesevorgang durch, um die Zeilenpositionen abzurufen (es liest also die gesamte Datei, behält aber nicht alles im Speicher), und dann führt jeder Zugriff eine Dateisuche nach der Tatsache durch.
Ich biete das obige Snippet unter der MIT- oder Apache-Lizenz nach Ermessen des Benutzers an.
quelle
Kann diese Funktion verwenden, um Zeile n zurückzugeben:
quelle