Lesen Sie die ersten N Zeilen einer Datei in Python

150

Wir haben eine große Rohdatendatei, die wir auf eine bestimmte Größe zuschneiden möchten. Ich habe Erfahrung mit .net c #, möchte dies jedoch in Python tun, um die Dinge zu vereinfachen und aus Interesse.

Wie würde ich vorgehen, um die ersten N Zeilen einer Textdatei in Python abzurufen? Wird das verwendete Betriebssystem Auswirkungen auf die Implementierung haben?

Russell
quelle
kann ich n als Kommandozeilenargument geben
Nons

Antworten:

241

Python 2

with open("datafile") as myfile:
    head = [next(myfile) for x in xrange(N)]
print head

Python 3

with open("datafile") as myfile:
    head = [next(myfile) for x in range(N)]
print(head)

Hier ist ein anderer Weg (sowohl Python 2 als auch 3)

from itertools import islice
with open("datafile") as myfile:
    head = list(islice(myfile, N))
print head
John La Rooy
quelle
1
Danke, das ist in der Tat sehr hilfreich. Was ist der Unterschied zwischen den beiden? (in Bezug auf Leistung, erforderliche Bibliotheken, Kompatibilität usw.)?
Russell
1
Ich erwarte eine ähnliche Leistung, vielleicht die erste, die etwas schneller ist. Der erste funktioniert jedoch nicht, wenn die Datei nicht mindestens N Zeilen enthält. Am besten messen Sie die Leistung anhand einiger typischer Daten, mit denen Sie sie verwenden werden.
John La Rooy
1
Die with-Anweisung funktioniert unter Python 2.6 und erfordert eine zusätzliche Importanweisung für 2.5. Für 2.4 oder früher müssten Sie den Code mit einem Versuch neu schreiben ... außer Block. Stilistisch bevorzuge ich die erste Option, obwohl die zweite, wie erwähnt, für kurze Dateien robuster ist.
Alasdair
1
islice ist wahrscheinlich schneller als es in C implementiert ist.
Alice Purcell
21
Denken Sie daran, dass, wenn die Dateien weniger als N Zeilen haben, dies eine StopIteration-Ausnahme auslöst, die Sie behandeln müssen
Ilian Iliev
19
N = 10
with open("file.txt", "a") as file:  # the a opens it in append mode
    for i in range(N):
        line = next(file).strip()
        print(line)
Ghostdog74
quelle
23
Ich zucke zusammen, wenn ich f = open("file")ausnahmslos die Behandlung sehe , um die Datei zu schließen. Die pythonische Art, mit Dateien umzugehen, ist mit einem Kontextmanager, dh mit der with-Anweisung. Dies wird im Python-Tutorial zur Eingabe und Ausgabe behandelt . "It is good practice to use the with keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way."
Mark Mikofski
1
Warum die Datei im Anhänge-Modus öffnen?
AMC
13

Wenn Sie die ersten Zeilen schnell lesen möchten und sich nicht um die Leistung kümmern, können Sie .readlines()das Listenobjekt "return" verwenden und dann die Liste aufteilen.

ZB für die ersten 5 Zeilen:

with open("pathofmyfileandfileandname") as myfile:
    firstNlines=myfile.readlines()[0:5] #put here the interval you want

Hinweis: Die gesamte Datei wird gelesen, ist also aus Sicht der Leistung nicht die beste, aber einfach zu verwenden, schnell zu schreiben und leicht zu merken. Wenn Sie also nur eine einmalige Berechnung durchführen möchten, ist dies sehr praktisch

print firstNlines

Ein Vorteil gegenüber den anderen Antworten ist die Möglichkeit, den Zeilenbereich einfach auszuwählen, z. B. die ersten 10 Zeilen [10:30]oder die letzten 10 Zeilen zu überspringen [:-10]oder nur gerade Zeilen zu nehmen [::2].

GM
quelle
2
Die beste Antwort ist wahrscheinlich viel effizienter, aber diese funktioniert wie ein Zauber für kleine Dateien.
T.Chmelevskij
2
Beachten Sie, dass dies tatsächlich zuerst die gesamte Datei in eine Liste liest (myfile.readlines ()) und dann die ersten 5 Zeilen davon zusammenfügt.
AbdealiJK
2
Dies sollte vermieden werden.
Anilbey
1
Ich sehe keinen Grund, dies zu nutzen, es ist nicht einfacher als die weitaus effizienteren Lösungen.
AMC
@AMC, danke für das Feedback. Ich verwende es in der Konsole, um die Daten zu untersuchen, wenn ich einen kurzen Blick auf die ersten Zeilen werfen muss. Das spart mir nur Zeit beim Schreiben von Code.
GM
9

Was ich tue, ist, die N Leitungen mit aufzurufen pandas. Ich denke, die Leistung ist nicht die beste, aber zum Beispiel, wenn N=1000:

import pandas as pd
yourfile = pd.read('path/to/your/file.csv',nrows=1000)
Cro-Magnon
quelle
3
Besser wäre es, die nrowsOption zu verwenden, die auf 1000 gesetzt werden kann und nicht die gesamte Datei lädt. pandas.pydata.org/pandas-docs/stable/generated/… Im Allgemeinen verfügt pandas über diese und andere speichersparende Techniken für große Dateien.
Philshem
Ja, du hast recht. Ich korrigiere es einfach. Entschuldige mich für den Fehler.
Cro-Magnon
1
Sie können auch hinzufügen sep, um einen Spaltenbegrenzer zu definieren (der in einer Nicht-CSV-Datei nicht vorkommen sollte)
Philshem
1
@ Cro-Magnon Ich kann die pandas.read()Funktion in der Dokumentation nicht finden. Kennen Sie Informationen zu diesem Thema?
AMC
6

Es gibt keine spezielle Methode zum Lesen der Anzahl der Zeilen, die vom Dateiobjekt angezeigt werden.

Ich denke, der einfachste Weg wäre folgender:

lines =[]
with open(file_name) as f:
    lines.extend(f.readline() for i in xrange(N))
Artdanil
quelle
Das war etwas, was ich eigentlich beabsichtigt hatte. Ich dachte jedoch daran, jede Zeile zur Liste hinzuzufügen. Danke dir.
Artdanil
4

Basierend auf der Antwort von Gnibbler (20. November 09 um 0:27 Uhr): Diese Klasse fügt dem Dateiobjekt die Methoden head () und tail () hinzu.

class File(file):
    def head(self, lines_2find=1):
        self.seek(0)                            #Rewind file
        return [self.next() for x in xrange(lines_2find)]

    def tail(self, lines_2find=1):  
        self.seek(0, 2)                         #go to end of file
        bytes_in_file = self.tell()             
        lines_found, total_bytes_scanned = 0, 0
        while (lines_2find+1 > lines_found and
               bytes_in_file > total_bytes_scanned): 
            byte_block = min(1024, bytes_in_file-total_bytes_scanned)
            self.seek(-(byte_block+total_bytes_scanned), 2)
            total_bytes_scanned += byte_block
            lines_found += self.read(1024).count('\n')
        self.seek(-total_bytes_scanned, 2)
        line_list = list(self.readlines())
        return line_list[-lines_2find:]

Verwendung:

f = File('path/to/file', 'r')
f.head(3)
f.tail(3)
fdb
quelle
4

Die zwei intuitivsten Möglichkeiten hierfür wären:

  1. Durchlaufen Sie die Datei Zeile für Zeile und breaknach NZeilen.

  2. Durchlaufen Sie die Datei Zeile für Zeile mit den next()Methodenzeiten N. (Dies ist im Wesentlichen nur eine andere Syntax für die Top-Antwort.)

Hier ist der Code:

# Method 1:
with open("fileName", "r") as f:
    counter = 0
    for line in f:
        print line
        counter += 1
        if counter == N: break

# Method 2:
with open("fileName", "r") as f:
    for i in xrange(N):
        line = f.next()
        print line

Unter dem Strich haben Sie viele Optionen , solange Sie nicht die gesamte Datei verwenden readlines()oder enumeratein den Speicher legen.

FatihAkici
quelle
3

der bequemste Weg für sich allein:

LINE_COUNT = 3
print [s for (i, s) in enumerate(open('test.txt')) if i < LINE_COUNT]

Lösung basierend auf Listenverständnis Die Funktion open () unterstützt eine Iterationsschnittstelle. Das enumerate () deckt open () ab und gibt Tupel (Index, Element) zurück. Dann überprüfen wir, ob wir uns innerhalb eines akzeptierten Bereichs befinden (wenn i <LINE_COUNT) und drucken dann einfach das Ergebnis.

Genieße den Python. ;)

Maxim Plaksin
quelle
Dies scheint nur eine etwas komplexere Alternative zu zu sein [next(file) for _ in range(LINE_COUNT)].
AMC
3

Für die ersten 5 Zeilen machen Sie einfach:

N=5
with open("data_file", "r") as file:
    for i in range(N):
       print file.next()
Surya
quelle
2

Wenn Sie etwas wollen, das offensichtlich (ohne esoterische Inhalte in Handbüchern nachzuschlagen) ohne Importe funktioniert, versuchen Sie es / ausgenommen und arbeiten Sie mit einer Reihe von Python 2.x-Versionen (2.2 bis 2.6):

def headn(file_name, n):
    """Like *x head -N command"""
    result = []
    nlines = 0
    assert n >= 1
    for line in open(file_name):
        result.append(line)
        nlines += 1
        if nlines >= n:
            break
    return result

if __name__ == "__main__":
    import sys
    rval = headn(sys.argv[1], int(sys.argv[2]))
    print rval
    print len(rval)
John Machin
quelle
2

Wenn Sie eine wirklich große Datei haben und davon ausgehen, dass die Ausgabe ein numpy-Array sein soll, friert die Verwendung von np.genfromtxt Ihren Computer ein. Das ist meiner Erfahrung nach so viel besser:

def load_big_file(fname,maxrows):
'''only works for well-formed text file of space-separated doubles'''

rows = []  # unknown number of lines, so use list

with open(fname) as f:
    j=0        
    for line in f:
        if j==maxrows:
            break
        else:
            line = [float(s) for s in line.split()]
            rows.append(np.array(line, dtype = np.double))
            j+=1
return np.vstack(rows)  # convert list of vectors to array
cacosomoza
quelle
Wenn Sie eine wirklich große Datei haben und davon ausgehen, dass die Ausgabe ein numpy-Array sein soll, das eine ziemlich einzigartige Reihe von Einschränkungen darstellt, kann ich gegenüber den Alternativen keine wirklichen Vorteile erkennen.
AMC
1

Ab Python 2.6 können Sie komplexere Funktionen in der IO-Basisklasse nutzen. Die oben am besten bewertete Antwort kann also wie folgt umgeschrieben werden:

    with open("datafile") as myfile:
       head = myfile.readlines(N)
    print head

(Sie müssen sich keine Sorgen machen, dass Ihre Datei weniger als N Zeilen enthält, da keine StopIteration-Ausnahme ausgelöst wird.)

Steve Bading
quelle
25
Gemäß den Dokumenten ist N die Anzahl der zu lesenden Bytes , nicht die Anzahl der Zeilen .
Mark Mikofski
4
N ist die Anzahl der Bytes!
Qed
5
Beeindruckend. Sprechen Sie über schlechte Benennung. Der Funktionsname erwähnt, linesaber das Argument bezieht sich auf bytes.
ArtOfWarfare
0

Das hat bei mir funktioniert

f = open("history_export.csv", "r")
line= 5
for x in range(line):
    a = f.readline()
    print(a)
Sukanta
quelle
Warum nicht einen Kontextmanager verwenden? Auf jeden Fall sehe ich nicht, wie sich dies gegenüber den vielen vorhandenen Antworten verbessert.
AMC
0

Dies funktioniert für Python 2 & 3:

from itertools import islice

with open('/tmp/filename.txt') as inf:
    for line in islice(inf, N, N+M):
        print(line)
Sandyp
quelle
Dies ist praktisch identisch mit der zehn Jahre alten Top-Antwort .
AMC
0

fname = input("Enter file name: ")
num_lines = 0

with open(fname, 'r') as f: #lines count
    for line in f:
        num_lines += 1

num_lines_input = int (input("Enter line numbers: "))

if num_lines_input <= num_lines:
    f = open(fname, "r")
    for x in range(num_lines_input):
        a = f.readline()
        print(a)

else:
    f = open(fname, "r")
    for x in range(num_lines_input):
        a = f.readline()
        print(a)
        print("Don't have", num_lines_input, " lines print as much as you can")


print("Total lines in the text",num_lines)
Shakirul
quelle
-1
#!/usr/bin/python

import subprocess

p = subprocess.Popen(["tail", "-n 3", "passlist"], stdout=subprocess.PIPE)

output, err = p.communicate()

print  output

Diese Methode hat bei mir funktioniert

Mansur Ali
quelle
Dies ist jedoch keine Python-Lösung.
AMC
Ich verstehe nicht einmal, was in Ihrer Antwort steht. Bitte fügen Sie eine Erklärung hinzu.
Alexei Marinichenko