2012-09-06 5 views
12

Possible Duplicate:
Get last n lines of a file with Python, similar to tail
Read a file in reverse order using pythonPython Lesen nur das Ende des großen Text

Datei Ich habe eine Datei, die in der Größe über 15 GB, es ist eine Protokolldatei, die ich angeblich aus der Ausgabe zu analysieren. Ich habe bereits eine grundlegende Analyse einer ähnlichen, aber sehr kleinen Datei mit nur wenigen Zeilen der Protokollierung durchgeführt. Parsing Strings ist nicht das Problem. Das Problem ist die riesige Datei und die Menge der redundanten Daten, die sie enthält.

Im Grunde versuche ich ein Python-Skript zu machen, das ich sagen könnte; Zum Beispiel, geben Sie mir 5000 letzte Zeilen der Datei. Das ist wieder grundlegend mit den Argumenten und all dem, nichts besonderes dort, das kann ich machen.

Aber wie definiere oder sage ich dem Dateileser, NUR die Zeilenanzahl zu lesen, die ich am Ende der Datei angegeben habe? Ich versuche, die huuuuuuge Menge an Zeilen am Anfang einer Datei zu überspringen, da ich nicht daran interessiert bin, und um ehrlich zu sein, dauert das Lesen von etwa 15 GB Zeilen aus einer TXT-Datei zu lange. Gibt es eine Möglichkeit, sich zu irren .. Lese von .. Ende der Datei? Macht das überhaupt Sinn?

Es läuft alles auf das Problem des Lesens einer 15GB-Datei ab, Zeile für Zeile dauert zu lange. Also möchte ich am Anfang die bereits redundanten Daten (zumindest für mich überflüssig) überspringen und nur die Zeilenanzahl vom Ende der Datei lesen, die ich lesen möchte.

Offensichtliche Antwort ist, manuell nur N Menge von Zeilen aus der Datei in eine andere Datei kopieren, aber gibt es eine Möglichkeit, dies halbautomatisch zu tun, nur um die Anzahl der Zeilen von dem Ende der Datei mit Python zu lesen ?

+0

Welches Betriebssystem verwenden Sie? –

+2

Keine direkte Antwort, aber wenn Sie nix verwenden, könnten Sie stattdessen die Eingabe von stdin akzeptieren und die Daten einfach mit 'tail riangilefile.txt -n1000 | senden python myprog.py' – moopet

+1

Siehe die Antworten auf die doppelte Frage. Der erste ist relativ plattformunabhängig, der zweite funktioniert gut auf UNIX-basierten Systemen (mit dem Befehl "tail" wie @moopet vorgeschlagen). –

Antwort

-1

Die bevorzugte Methode zu diesem Zeitpunkt war, einfach Unix-Tail für den Job zu verwenden und den Python so zu modifizieren, dass Eingaben über die Std-Eingabe akzeptiert werden.

tail hugefile.txt -n1000 | python magic.py 

Es ist nichts sexy, aber zumindest kümmert es sich um den Job. Die große Datei ist eine zu große Last, um damit umzugehen, fand ich heraus. Zumindest für meine Python-Fähigkeiten. Es war also viel einfacher, nur eine Prise Nix-Magie hinzuzufügen, um die Dateigröße zu reduzieren. Der Schwanz war neu für mich. Habe etwas gelernt und finde eine andere Möglichkeit, das Terminal wieder zu meinem Vorteil zu nutzen. Danke euch allen.

4

Farm diese in die Unix-out:

import os 
os.popen('tail -n 1000 filepath').read() 

Verwendung anstelle von os.popen subprocess.Popen, wenn Sie für den Zugriff auf stderr in der Lage sein müssen (und einige andere Features)

+0

Viele durchdachte Antworten in diesem Thread, aber für praktische Zwecke scheint Ihre Antwort am relevantesten zu sein - verdient einen höheren Rang! – isosceleswheel

0

Auch wenn ich es vorziehen würde, die "Tail" -Lösung - Wenn Sie die maximale Anzahl an Zeichen pro Zeile kennen, können Sie eine andere mögliche Lösung implementieren, indem Sie die Dateigröße öffnen, einen Dateihandler öffnen und die 'seek' Methode mit einer geschätzten Anzahl von Zeichen verwenden zum.

Dieser letzte Code sollte so aussehen - nur um zu erklären, warum ich auch die Schwanzlösung bevorzuge :) goodluck!

MAX_CHARS_PER_LINE = 80 
size_of_file = os.path.getsize('15gbfile.txt') 
file_handler = file.open('15gbfile.txt', "rb") 
seek_index = size_of_file - (number_of_requested_lines * MAX_CHARS_PER_LINE) 
file_handler.seek(seek_index) 
buffer = file_handler.read() 

Sie können diesen Code verbessern, indem Sie neue Zeilen des gelesenen Puffers analysieren. Viel Glück (und Sie sollten die Schwanz-Lösung verwenden ;-) ich bin ziemlich sicher, dass Sie Schwanz für jedes OS bekommen)

11

Sie müssen mit dem Ende der Datei suchen, dann lesen Sie ein paar Brocken in Blöcken von das Ende, Zeilen zählen, bis Sie genügend Zeilenumbrüche gefunden haben, um Ihre n Zeilen zu lesen.

Im Grunde implementieren Sie eine einfache Form des Tails.

Hier einig leicht getestet Code, der das tut nur:

import os, errno 

def lastlines(hugefile, n, bsize=2048): 
    # get newlines type, open in universal mode to find it 
    with open(hugefile, 'rU') as hfile: 
     if not hfile.readline(): 
      return # empty, no point 
     sep = hfile.newlines # After reading a line, python gives us this 
    assert isinstance(sep, str), 'multiple newline types found, aborting' 

    # find a suitable seek position in binary mode 
    with open(hugefile, 'rb') as hfile: 
     hfile.seek(0, os.SEEK_END) 
     linecount = 0 
     pos = 0 

     while linecount <= n + 1: 
      # read at least n lines + 1 more; we need to skip a partial line later on 
      try: 
       hfile.seek(-bsize, os.SEEK_CUR)   # go backwards 
       linecount += hfile.read(bsize).count(sep) # count newlines 
       hfile.seek(-bsize, os.SEEK_CUR)   # go back again 
      except IOError, e: 
       if e.errno == errno.EINVAL: 
        # Attempted to seek past the start, can't go further 
        bsize = hfile.tell() 
        hfile.seek(0, os.SEEK_SET) 
        linecount += hfile.read(bsize).count(sep) 
        break 
       raise # Some other I/O exception, re-raise 
      pos = hfile.tell() 

    # Re-open in text mode 
    with open(hugefile, 'r') as hfile: 
     hfile.seek(pos, os.SEEK_SET) # our file position from above 

     for line in hfile: 
      # We've located n lines *or more*, so skip if needed 
      if linecount > n: 
       linecount -= 1 
       continue 
      # The rest we yield 
      yield line 
+0

Wie drucken Sie die abgeleiteten Linien? – Superdooperhero

+0

Gibt mir: Traceback (letzten Anruf zuletzt): Datei "tail3.py", Zeile 45, in letzten Zeilen (r "E: \ D_Backup \ Downloads \ googlebooks-eng-all-2gram-20120701-_NOUN_", 1000, bsize = 2048) Datei "tail3.py", Zeile 21, in letzten Zeilen linecount + = hfile.read (bsize) .count (sep) # Anzahl Zeilenumbrüche TypeError: ein Byte-ähnliches Objekt ist erforderlich, nicht ' str ' – Superdooperhero

+1

@Superdooperhero: Der Code wurde für Python 2, nicht Python 3 geschrieben. Sie müssten 'sep.encode()' verwenden, um stattdessen ein 'bytes'-Objekt zu erhalten. –

Verwandte Themen