Frage

Gibt es Alternativen zu dem 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 Linien von unbekannter, aber unterschiedlicher Länge verarbeiten und muß auf eine bestimmte Linie, der Nummer, die ich im Voraus springen? Ich fühle mich schlecht, indem sie eine Verarbeitung durch ein, wenn ich weiß, dass ich zumindest erste Hälfte der Datei ignorieren konnte. Suche nach mehr eleganten Lösung, wenn es irgendwelche gibt.

War es hilfreich?

Lösung

linecache :

  

Das linecache Modul ermöglicht eine beliebige Linie zu bekommen aus eine Python-Quelldatei, bei dem Versuch, intern zu optimieren, einen Cache, den gemeinsamen Fall mit der vielen Zeilen aus einer einzigen Datei gelesen werden. Dies wird von der traceback Modul Quellenleitungen für die Aufnahme Abrufen in den formatierten Zurückverfolgungs ...

Andere Tipps

Sie können nicht weiter springen in der Datei mindestens einmal, ohne zu lesen, da Sie nicht wissen, wo die Zeilenumbrüche sind. Sie könnten wie etwas tun:

# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
for line in file:
    line_offset.append(offset)
    offset += len(line)
file.seek(0)

# Now, to skip to line n (with the first line being line 0), just do
file.seek(line_offset[n])

Sie haben nicht wirklich haben, dass viele Optionen, wenn die Linien unterschiedlicher Länge sind ... Sie leider die Zeilenende Zeichen verarbeiten müssen, um zu wissen, wann Sie in der nächsten Zeile fortgeschritten haben.

Sie können dies jedoch dramatisch beschleunigen und Speicherverbrauch zu reduzieren, indem die letzten Parameter Wechsel zu „öffnen“, um etwas nicht 0.

0 bedeutet, dass der Datei-Lesevorgang ungepufferte ist, was sehr langsam ist und die Scheibe intensiv. 1 bedeutet, dass die Datei Zeile gepuffert wird, was eine Verbesserung wäre. Alles, was über 1 (sagen wir 8k .. also: 8096 oder höher) liest Stücke der Datei in den Speicher. Sie greifen sie immer noch durch for line in open(etc):, aber Python geht nur ein wenig in einer Zeit, jeden gepufferte chunk Verwerfen nach seinem verarbeitet werden.

Ich bin wahrscheinlich durch reichlich RAM verdorben, aber 15 M ist nicht riesig. Lesen in den Speicher mit readlines() ist das, was ich in der Regel mit Dateien dieser Größe zu tun. Der Zugriff auf eine Linie danach trivial ist.

Da es keine Möglichkeit gibt, die Länge aller Linien zu bestimmen, ohne sie zu lesen, Sie haben keine andere Wahl, als alle Zeilen vor Ihrer Startlinie iterieren. Alles, was Sie tun können, ist es schön aussehen zu lassen. Wenn die Datei wirklich riesig ist dann möchten Sie vielleicht einen Generator basierten Ansatz verwenden:

from itertools import dropwhile

def iterate_from_line(f, start_from_line):
    return (l for i, l in dropwhile(lambda x: x[0] < start_from_line, enumerate(f)))

for line in iterate_from_line(open(filename, "r", 0), 141978):
    DoSomethingWithThisLine(line)

. Hinweis: der Index Null basierend auf diesem Ansatz

Ich bin überrascht, niemand Islice erwähnt

line = next(itertools.islice(Fhandle,index_of_interest,index_of_interest+1),None) # just the one line

oder wenn Sie den ganzen Rest der Datei wollen

rest_of_file = itertools.islice(Fhandle,index_of_interest)
for line in rest_of_file:
    print line

oder wenn Sie jede zweite Zeile aus der Datei mögen

rest_of_file = itertools.islice(Fhandle,index_of_interest,None,2)
for odd_line in rest_of_file:
    print odd_line

Wenn Sie im Voraus die Position in der Datei (und nicht die Zeilennummer) kennen, können Sie "http://docs.python.org/library/stdtypes.html#file.seek" verwenden file.seek () zu dieser Position zu gehen.

Bearbeiten : Sie können die linecache. getline (Dateiname, lineno) -Funktion, die den Inhalt der Zeile lineno zurück, aber erst, nachdem die gesamte Datei in dem Speicher zu lesen. Gut, wenn Sie zufällig Zeilen aus der Datei zugreifen (wie Python selbst wünschen kann tun, um eine Rückverfolgung zu drucken), aber nicht gut für eine 15 MB-Datei.

Wenn Sie nicht die gesamte Datei in dem Speicher lesen wollen .. Sie können mit etwas anderen Format als Klartext benötigen kommen.

natürlich alles hängt davon ab, was Sie zu tun versuchen, und wie oft Sie über die Datei springen.

Zum Beispiel, wenn du wirst zu den Linien springen werden oft in der gleichen Datei, und Sie wissen, dass die Datei während ändert sich nicht mit ihr arbeiten, können Sie dies tun:
Zuerst geht durch die gesamte Datei, und notieren Sie die „Such-Position“ einige Schlüssel-line-Zahlen (wie je 1000 Zeilen), Frankreich Dann, wenn Sie 12.005 wollen Linie, springe zur Position von 12000 (die Sie aufgenommen haben) lesen dann 5 Zeilen, und Sie werden wissen, dass Sie in Zeile sind 12005 und so weiter

Was erzeugt die Datei, die Sie bearbeiten möchten? Wenn es etwas unter Ihrer Kontrolle ist, können Sie einen Index erzeugen (die Linie, an der Position befindet.) Zum Zeitpunkt der Datei zu angefügt wird. Die Indexdatei von Festnetz Größe sein kann (Raum aufgefüllt oder 0 gepolsterte Zahlen) und wird auf jeden Fall kleiner sein. Und so kann qucikly gelesen und verarbeitet werden.

  • Welche Linie wollen Sie ?.
  • Berechnen Byte entsprechenden Zeilennummer in Indexdatei-Offset (möglich, weil Zeilengröße der Indexdatei ist konstant).
  • Verwenden Sie suchen oder was auch immer zu springen direkt die Zeile aus dem Index-Datei zu erhalten.
  • Parse Byte-Offset für entsprechende Zeile der aktuellen Datei zu erhalten.

Ich habe das gleiche Problem hatte (müssen aus riesigen Datei bestimmte Zeile abgerufen werden).

Sicher, kann ich jedes Mal durch alle Datensätze in der Datei ausgeführt werden und es stoppen, wenn der Zähler gleich seine Linie zum Ziel, aber es funktioniert nicht effektiv in einem Fall, wenn Sie mehrfache Anzahl von bestimmten Zeilen erhalten mögen. Das verursachte Hauptproblem gelöst werden -. Wie direkt zu dem notwendigen Platz für die Datei verarbeitet

fand ich nächste Entscheidung aus: Zunächst absolvierte ich Wörterbuch mit Startposition jeder Zeile (Schlüssel ist, Zeilennummer und Wert - kumulierte Länge der vorherigen Linien).

t = open(file,’r’)
dict_pos = {}

kolvo = 0
length = 0
for each in t:
    dict_pos[kolvo] = length
    length = length+len(each)
    kolvo = kolvo+1

schließlich wollen Funktion:

def give_line(line_number):
    t.seek(dict_pos.get(line_number))
    line = t.readline()
    return line

t.seek (line_number) - Befehl, die Beschneidung der Datei ausführen bis Anfang auszukleiden. Also, wenn Sie das nächste Readline- begehen -. Sie Ihre Ziellinie erhalten

solchen Ansatz Ich habe erheblichen Teil der Zeit gespeichert.

Haben die Linien selbst alle Indexinformationen enthalten? Wenn der Inhalt jeder Zeile so etwas wie „<line index>:Data“ ist, dann könnte der seek() Ansatz verwendet werden, um eine binäre Suche durch die Datei zu tun, auch wenn die Menge an Data variabel ist. Sie würden auf den Mittelpunkt der Datei suchen, eine Zeile lesen, prüfen, ob sein Index höher oder niedriger ist als die, die Sie wollen, etc.

Ansonsten ist das Beste, was Sie tun können, ist nur readlines(). Wenn Sie nicht alle 15MB lesen möchten, können Sie das sizehint Argument zumindest eine Menge readline()s mit einer kleineren Anzahl von Anrufen ersetzen readlines().

Hier ist ein Beispiel ‚readlines (sizeHint)‘ mit einem Stück von Linien zu einem Zeitpunkt, zu lesen. DNS wies diese Lösung aus. Ich schrieb dieses Beispiel, weil die andere hier Beispiele einzeilige orientiert.

sind
def getlineno(filename, lineno):
    if lineno < 1:
        raise TypeError("First line is line 1")
    f = open(filename)
    lines_read = 0
    while 1:
        lines = f.readlines(100000)
        if not lines:
            return None
        if lines_read + len(lines) >= lineno:
            return lines[lineno-lines_read-1]
        lines_read += len(lines)

print getlineno("nci_09425001_09450000.smi", 12000)

Sie können Mmap verwenden den Versatz der Linien zu finden. MMAP scheint der schnellste Weg, um eine Datei zu verarbeiten

Beispiel:

with open('input_file', "r+b") as f:
    mapped = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
    i = 1
    for line in iter(mapped.readline, ""):
        if i == Line_I_want_to_jump:
            offsets = mapped.tell()
        i+=1

dann f.seek (Offsets) verwenden zu bewegen, um die Zeile Sie benötigen

Wenn Sie mit einem zu tun hat Textdatei & basierend auf Linux-System , können Sie die Linux-Befehle verwenden.
Für mich war das gut!

import commands

def read_line(path, line=1):
    return commands.getoutput('head -%s %s | tail -1' % (line, path))

line_to_jump = 141978
read_line("path_to_large_text_file", line_to_jump)

Kann diese Funktion verwenden, um Zeile n zurück:

def skipton(infile, n):
    with open(infile,'r') as fi:
        for i in range(n-1):
            fi.next()
        return fi.next()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top