Przeczytaj pierwsze N ​​wierszy pliku w pythonie


150

Mamy duży plik nieprzetworzonych danych, który chcielibyśmy przyciąć do określonego rozmiaru. Mam doświadczenie w .net C #, jednak chciałbym to zrobić w Pythonie, aby uprościć i zaciekawić.

Jak zabrać się do uzyskania pierwszych N wierszy pliku tekstowego w Pythonie? Czy używany system operacyjny będzie miał jakikolwiek wpływ na implementację?


czy mogę podać n jako argument wiersza poleceń
Nons

Odpowiedzi:


240

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)

Oto inny sposób (zarówno Python 2, jak i 3)

from itertools import islice
with open("datafile") as myfile:
    head = list(islice(myfile, N))
print head

1
Dzięki, to rzeczywiście bardzo pomocne. Jaka jest różnica między nimi? (pod względem wydajności, wymaganych bibliotek, kompatybilności itp.)?
Russell

1
Spodziewam się, że wydajność będzie podobna, może pierwsza będzie nieco szybsza. Ale pierwsza nie zadziała, jeśli plik nie zawiera co najmniej N linii. Najlepiej jest mierzyć wydajność w odniesieniu do niektórych typowych danych, z którymi będziesz go używać.
John La Rooy

1
Instrukcja with działa w Pythonie 2.6 i wymaga dodatkowej instrukcji importu w wersji 2.5. W przypadku wersji 2.4 lub wcześniejszej musiałbyś przepisać kod za pomocą try ... oprócz bloku. Stylistycznie wolę pierwszą opcję, chociaż jak wspomniano, druga jest bardziej wytrzymała dla krótkich plików.
Alasdair

1
islice jest prawdopodobnie szybsze, ponieważ jest zaimplementowane w C.
Alice Purcell

22
Pamiętaj, że jeśli pliki mają mniej niż N wierszy, spowoduje to powstanie wyjątku StopIteration, z którym musisz sobie poradzić
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)

23
Wzdrygam się, gdy widzę f = open("file")bez wyjątku obsługę zamykania pliku. Pythonowym sposobem obsługi plików jest użycie menedżera kontekstu, tj. Użycie instrukcji with. Jest to omówione w samouczku Pythona z danymi wejściowymi . "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
Po co otwierać plik w trybie dołączania?
AMC

13

Jeśli chcesz szybko przeczytać pierwsze wiersze i nie zależy Ci na wydajności, możesz użyć funkcji, .readlines()która zwraca obiekt listy, a następnie wyciąć listę.

Np. Dla pierwszych 5 linii:

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

Uwaga: cały plik jest odczytywany, więc nie jest najlepszy z punktu widzenia wydajności, ale jest łatwy w użyciu, szybki do napisania i łatwy do zapamiętania, więc jeśli chcesz po prostu wykonać jednorazowe obliczenia, jest to bardzo wygodne

print firstNlines

Jedną z zalet w porównaniu z innymi odpowiedziami jest możliwość łatwego wyboru zakresu linii, np. Pomijanie pierwszych 10 wierszy [10:30]lub ostatnich 10 wierszy [:-10]lub branie tylko parzystych wierszy [::2].


2
Najlepsza odpowiedź jest prawdopodobnie bardziej wydajna, ale ta działa jak urok w przypadku małych plików.
T.Chmelevskij

2
Zauważ, że to faktycznie wczytuje najpierw cały plik na listę (myfile.readlines ()), a następnie łączy pierwsze 5 linii z niej.
AbdealiJK

2
Należy tego unikać.
anilbey

1
Nie widzę powodu, aby z tego korzystać, nie jest to prostsze niż znacznie wydajniejsze rozwiązania.
AMC

@AMC dzięki za informację zwrotną, używam go w konsoli do eksploracji danych, gdy muszę szybko przejrzeć pierwsze linie, oszczędza mi to tylko czas na pisanie kodu.
GM

9

To, co robię, to wywoływać linie N za pomocą pandas. Myślę, że wykonanie nie jest najlepsze, ale np. Jeśli N=1000:

import pandas as pd
yourfile = pd.read('path/to/your/file.csv',nrows=1000)

3
Lepiej byłoby użyć nrowsopcji, którą można ustawić na 1000, a cały plik nie jest ładowany. pandas.pydata.org/pandas-docs/stable/generated/... Ogólnie pandy mają tę i inne techniki oszczędzania pamięci dla dużych plików.
philshem

Tak masz rację. Po prostu to poprawiam. Przepraszam za błąd.
Cro-Magnon

1
Możesz również chcieć dodać, sepaby zdefiniować ogranicznik kolumny (który nie powinien występować w pliku innym niż CSV)
philshem

1
@ Cro-Magnon Nie mogę znaleźć pandas.read()funkcji w dokumentacji, czy znasz jakieś informacje na ten temat?
AMC

6

Nie ma określonej metody odczytywania liczby wierszy ujawnionych przez obiekt pliku.

Myślę, że najłatwiejszym sposobem byłoby wykonanie następujących czynności:

lines =[]
with open(file_name) as f:
    lines.extend(f.readline() for i in xrange(N))

To jest coś, co właściwie zamierzałem. Chociaż myślałem o dodaniu każdego wiersza do listy. Dziękuję Ci.
artdanil

4

Na podstawie odpowiedzi gnibbler najczęściej głosowanych (20 listopada 2009 o godzinie 0:27): ta klasa dodaje metody head () i tail () do obiektu pliku.

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:]

Stosowanie:

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

4

Oto dwa najbardziej intuicyjne sposoby:

  1. Iteruj po pliku wiersz po wierszu i breakpo Nwierszach.

  2. Iteruj na pliku wiersz po wierszu, używając czasów next()metody N. (Zasadniczo jest to po prostu inna składnia tego, co robi pierwsza odpowiedź).

Oto kod:

# 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

Najważniejsze jest to, że jeśli nie używasz readlines()lub nie enumeratezapisujesz całego pliku w pamięci, masz wiele opcji.


3

najbardziej wygodny sposób we własnym zakresie:

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

Rozwiązanie oparte na zrozumieniu listy Funkcja open () obsługuje interfejs iteracyjny. Enumerate () obejmuje open () i zwracające krotki (indeks, element), następnie sprawdzamy, czy znajdujemy się w akceptowanym zakresie (jeśli i <LINE_COUNT), a następnie po prostu drukujemy wynik.

Ciesz się Pythonem. ;)


Wydaje się, że jest to nieco bardziej złożona alternatywa dla [next(file) for _ in range(LINE_COUNT)].
AMC

3

W przypadku pierwszych 5 linii po prostu wykonaj:

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

2

Jeśli chcesz czegoś, co oczywiście (bez szukania ezoterycznych rzeczy w podręcznikach) działa bez importu i spróbuj / z wyjątkiem i działa na sporej liczbie wersji Pythona 2.x (2.2 do 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)

2

Jeśli masz naprawdę duży plik i zakładając, że chcesz, aby wynik był tablicą numpy, użycie np.genfromtxt spowoduje zawieszenie komputera. Z mojego doświadczenia wynika o wiele lepiej:

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

Jeśli masz naprawdę duży plik i zakładając, że chcesz, aby wynik był tablicą numpy. Jest to dość unikalny zestaw ograniczeń, nie widzę w tym żadnej przewagi nad alternatywami.
AMC

1

Począwszy od Pythona 2.6, możesz skorzystać z bardziej wyrafinowanych funkcji w podstawowej klasie IO. Zatem najwyżej ocenianą odpowiedź powyżej można przepisać jako:

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

(Nie musisz się martwić, że plik ma mniej niż N wierszy, ponieważ nie jest zgłaszany żaden wyjątek StopIteration).


25
Zgodnie z dokumentacją N to liczba bajtów do odczytania, a nie liczba wierszy .
Mark Mikofski

4
N to liczba bajtów!
okazania

5
Łał. Porozmawiaj o złym nazewnictwie. Nazwa funkcji wspomina, linesale argument odnosi się do bytes.
ArtOfWarfare

0

To zadziałało dla mnie

f = open("history_export.csv", "r")
line= 5
for x in range(line):
    a = f.readline()
    print(a)

Dlaczego nie skorzystać z menedżera kontekstu? W każdym razie nie widzę, jak poprawi się to w przypadku wielu istniejących odpowiedzi.
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)

-1
#!/usr/bin/python

import subprocess

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

output, err = p.communicate()

print  output

Ta metoda zadziałała dla mnie


To nie jest jednak tak naprawdę rozwiązanie Pythona.
AMC

Nie rozumiem nawet, co jest napisane w Twojej odpowiedzi. Proszę dodać wyjaśnienie.
Alexei Marinichenko
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.