Czytanie tylko określonych linii


Odpowiedzi:


253

Jeśli plik do odczytu jest duży i nie chcesz jednocześnie czytać całego pliku w pamięci:

fp = open("file")
for i, line in enumerate(fp):
    if i == 25:
        # 26th line
    elif i == 29:
        # 30th line
    elif i > 29:
        break
fp.close()

Zauważ, że i == n-1dla nlinii th.


W Pythonie 2.6 lub nowszym:

with open("file") as fp:
    for i, line in enumerate(fp):
        if i == 25:
            # 26th line
        elif i == 29:
            # 30th line
        elif i > 29:
            break

8
enumerate(x)używa x.next, więc nie potrzebuje całego pliku w pamięci.
Alok Singhal

3
Moja mała wołowina polega na tym, że A) chcesz używać zamiast pary otwarta / zamknięta, a tym samym utrzymywać ciało krótkie, B) Ale ciało nie jest tak krótkie. Brzmi jak kompromis między prędkością / przestrzenią a byciem Pythonem. Nie jestem pewien, jakie byłoby najlepsze rozwiązanie.
Hamish Grubijan,

5
z jest przereklamowany, python radził sobie dobrze bez niego przez ponad 13 lat
Dan D.

38
@Dan D. Elektryczność jest przereklamowana, bez niej ludzkość dobrze sobie radzi przez ponad 200 tysięcy lat. ;-) „with” czyni go bezpieczniejszym, bardziej czytelnym i krótszym o jedną linię.
Romain Vincent

9
dlaczego używać pętli, nie sądzę, że rozumiesz znaczenie big file. Pętla zajmie lata, aby dotrzeć do indeksu
devssh

159

Szybka odpowiedź:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]

lub:

lines=[25, 29]
i=0
f=open('filename')
for line in f:
    if i in lines:
        print i
    i+=1

Istnieje bardziej eleganckie rozwiązanie do wyodrębniania wielu wierszy: linecache (dzięki uprzejmości „python: jak przejść do konkretnej linii w ogromnym pliku tekstowym?” , Poprzednie pytanie stackoverflow.com).

Cytując powyższą dokumentację w języku Python:

>>> import linecache
>>> linecache.getline('/etc/passwd', 4)
'sys:x:3:3:sys:/dev:/bin/sh\n'

Zmień 4żądany numer linii i gotowe. Zauważ, że 4 przyniosłoby piątą linię, ponieważ liczba jest liczona od zera.

Jeśli plik może być bardzo duży i powodować problemy podczas wczytywania do pamięci, dobrym pomysłem może być skorzystanie z porady @ Alok i użycie funkcji enumerate () .

Podsumowując:

  • Użyj fileobject.readlines()lub for line in fileobjectjako szybkiego rozwiązania dla małych plików.
  • Użyj linecachedo bardziej eleganckiego rozwiązania, które będzie dość szybkie do odczytu wielu plików, możliwe wielokrotnie.
  • Skorzystaj z porad @ Aloka i użyjenumerate() plików, które mogą być bardzo duże i nie zmieściłyby się w pamięci. Pamiętaj, że użycie tej metody może spowolnić, ponieważ plik jest odczytywany sekwencyjnie.

7
Miły. Właśnie spojrzałem na źródło linecachemodułu i wygląda na to, że czyta cały plik z pamięci. Tak więc, jeśli losowy dostęp jest ważniejszy niż optymalizacja rozmiaru, linecachejest najlepszą metodą.
Alok Singhal

7
z linecache.getlin ('some_file', 4) Dostaję czwartą linię, a nie piątą.
Juan

fajny fakt: jeśli użyjesz zestawu zamiast listy w drugim przykładzie, otrzymasz czas działania O (1). Wyszukiwanie na liście to O (n). Zestawy wewnętrzne są reprezentowane jako skróty i dlatego otrzymujesz czas działania O (1). w tym przykładzie nie jest to wielka sprawa, ale jeśli używasz dużej listy liczb i zależy Ci na wydajności, to zestawy są właściwą drogą.
rady

linecacheteraz wydaje się działać tylko dla plików źródłowych Pythona
Paul H

Możesz także użyć linecache.getlines('/etc/passwd')[0:4]do czytania pierwszego, drugiego, trzeciego i czwartego wiersza.
zyy

30

Szybkie i kompaktowe podejście mogłoby być:

def picklines(thefile, whatlines):
  return [x for i, x in enumerate(thefile) if i in whatlines]

akceptuje to dowolny otwarty obiekt podobny do pliku thefile(pozostawiając programowi wywołującemu, czy należy go otworzyć z pliku dyskowego, czy np. przez gniazdo lub inny strumień podobny do pliku) i zestaw wskaźników wiersza od zera whatlines, i zwraca lista, z małą powierzchnią pamięci i rozsądną prędkością. Jeśli liczba zwracanych wierszy jest ogromna, możesz preferować generator:

def yieldlines(thefile, whatlines):
  return (x for i, x in enumerate(thefile) if i in whatlines)

co w zasadzie jest dobre tylko do zapętlania - zwróć uwagę, że jedyna różnica wynika z użycia w returninstrukcji zaokrąglonych, a nie kwadratowych nawiasów , dzięki czemu możliwe jest zrozumienie listy i wyrażenie generatora.

Zwróć też uwagę, że pomimo wzmianki o „wierszach” i „pliku” funkcje te są znacznie, znacznie bardziej ogólne - będą działać na każdym iterowalnym, czy to otwartym pliku, czy innym, zwracając listę (lub generator) elementów na podstawie ich progresywnych numerów przedmiotów. Sugeruję więc stosowanie bardziej odpowiednio ogólnych nazw ;-).


@ephemient, nie zgadzam się - genexp czyta płynnie i idealnie.
Alex Martelli

Doskonałe i eleganckie rozwiązanie, dzięki! Rzeczywiście, nawet duże pliki powinny być obsługiwane z wyrażeniem generatora. Nie może być bardziej elegancki niż to, prawda? :)
Samuel Lampa

Ładne rozwiązanie, jak to się ma do proponowanego przez @AdamMatan? Rozwiązanie Adama może być szybsze, ponieważ wykorzystuje dodatkowe informacje (monotonicznie rosnące numery linii), które mogą prowadzić do wczesnego zatrzymania. Mam plik 10 GB, którego nie mogę załadować do pamięci.
Mannaggia

2
@Mannaggia Nie jest wystarczająco podkreślone w tej odpowiedzi, ale whatlinespowinno być set, ponieważ if i in whatlinesbędzie działać szybciej z zestawem niż (posortowaną) listą. Nie zauważyłem tego po raz pierwszy i zamiast tego opracowałem własne brzydkie rozwiązanie z posortowaną listą (gdzie nie musiałem skanować listy za każdym razem, podczas gdyif i in whatlines tylko to robi), ale różnica w wydajności była znikoma (z moimi danymi) i to rozwiązanie jest znacznie bardziej eleganckie.
Victor K

28

Aby zaoferować inne rozwiązanie:

import linecache
linecache.getline('Sample.txt', Number_of_Line)

Mam nadzieję, że to szybkie i łatwe :)


1
Mam nadzieję, że jest to najbardziej optymalne rozwiązanie.
maniac_user

2
Odczytuje to cały plik do pamięci. Równie dobrze możesz wywołać file.read (). Split ('\ n'), a następnie użyć odnośników indeksu tablic, aby uzyskać linię zainteresowania ...
duhaime

Czy możesz podać przykład @duhaime
anon

14

jeśli chcesz wiersz 7

line = open („file.txt”, „r”). readlines () [7]

14
Schludny. Ale jak ci się podoba close()plik, otwierając go w ten sposób?
Milo Wielondek

1
@ 0sh czy musimy zamknąć?
Ooker

1
tak. po tym musimy zamknąć. Kiedy otwieramy plik za pomocą „z” ... zamyka się.
reetesh11

10

Dla kompletności, oto jeszcze jedna opcja.

Zacznijmy od definicji z dokumentacji Pythona :

plasterek Obiekt zwykle zawierający część sekwencji. Wycinek jest tworzony za pomocą notacji indeksu dolnego [] z dwukropkami między liczbami, gdy podano kilka, na przykład w zmiennej_nazwa [1: 3: 5]. Notacja w nawiasach (indeks dolny) wykorzystuje obiekty wycinków wewnętrznie (lub w starszych wersjach __getslice __ () i __setslice __ ()).

Chociaż notacja wycinka nie ma bezpośredniego zastosowania do iteratorów, itertoolspakiet zawiera funkcję zastępowania:

from itertools import islice

# print the 100th line
with open('the_file') as lines:
    for line in islice(lines, 99, 100):
        print line

# print each third line until 100
with open('the_file') as lines:
    for line in islice(lines, 0, 100, 3):
        print line

Dodatkową zaletą tej funkcji jest to, że nie czyta iteratora do końca. Możesz więc robić bardziej złożone rzeczy:

with open('the_file') as lines:
    # print the first 100 lines
    for line in islice(lines, 100):
        print line

    # then skip the next 5
    for line in islice(lines, 5):
        pass

    # print the rest
    for line in lines:
        print line

Aby odpowiedzieć na pierwotne pytanie:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]

1
Zdecydowanie najlepsze podejście do pracy z dużymi plikami. Mój program przeszedł z konsumpcji 8 GB + na prawie nic. Kompromisem było zużycie procesora, które wzrosło z ~ 15% do ~ 40%, ale faktyczne przetwarzanie pliku było o 70% szybsze. Będę to kompromis przez cały dzień. Dzięki Ci! 🎉🎉🎉
GollyJer

1
Wydaje mi się to najbardziej pytoniczne. Dzięki!
ipetrik

10

Odczytywanie plików jest niesamowicie szybkie. Odczyt pliku 100 MB zajmuje mniej niż 0,1 sekundy (zobacz mój artykuł Odczytywanie i zapisywanie plików w Pythonie ). Dlatego powinieneś przeczytać go całkowicie, a następnie pracować z pojedynczymi wierszami.

Większość odpowiedzi tutaj nie jest zła, ale zły styl. Zawsze należy otwierać plikiwith ponieważ zapewnia to, że plik zostanie ponownie zamknięty.

Więc powinieneś to zrobić w ten sposób:

with open("path/to/file.txt") as f:
    lines = f.readlines()
print(lines[26])  # or whatever you want to do with this line
print(lines[30])  # or whatever you want to do with this line

Ogromne pliki

Jeśli zdarzy ci się mieć ogromny plik i zużycie pamięci stanowi problem, możesz go przetworzyć wiersz po wierszu:

with open("path/to/file.txt") as f:
    for i, line in enumerate(f):
        pass  # process line i

IMO to naprawdę zły styl, aby przeczytać cały plik o nieznanej długości, tylko po to, aby uzyskać pierwsze 30 wierszy .. co jest z zużyciem pamięci .. a co z niekończącymi się strumieniami?
return42

@ return42 To zależy bardzo od aplikacji. Dla wielu jest całkowicie w porządku założyć, że plik tekstowy ma znacznie mniejszy rozmiar niż dostępna pamięć. Jeśli zdarzy ci się mieć potencjalnie ogromne pliki, zredagowałem moją odpowiedź.
Martin Thoma,

dzięki za dodanie, które jest takie samo jak odpowiedź alok . I przepraszam nie, nie sądzę, że to zależy od aplikacji. IMO zawsze lepiej nie czytaj więcej linii niż potrzebujesz.
return42

7

Niektóre z nich są piękne, ale można to zrobić o wiele prościej:

start = 0 # some starting index
end = 5000 # some ending index
filename = 'test.txt' # some file we want to use

with open(filename) as fh:
    data = fin.readlines()[start:end]

print(data)

Wykorzysta to proste wycinanie list, ładuje cały plik, ale większość systemów odpowiednio zminimalizuje zużycie pamięci, jest szybsza niż większość metod podanych powyżej i działa na moich plikach danych 10G +. Powodzenia!


4

Możesz wykonać wywołanie seek (), które pozycjonuje twoją głowicę odczytu do określonego bajtu w pliku. To ci nie pomoże, chyba że dokładnie wiesz, ile bajtów (znaków) zapisano w pliku przed wierszem, który chcesz przeczytać. Być może twój plik jest ściśle sformatowany (każda linia ma liczbę X bajtów?) Lub możesz sam policzyć liczbę znaków (pamiętaj o dołączaniu niewidocznych znaków, takich jak podział linii), jeśli naprawdę chcesz przyspieszenia.

W przeciwnym razie musisz przeczytać każdą linię przed linią, której chcesz, zgodnie z jednym z wielu rozwiązań już tutaj zaproponowanych.


3

Jeśli twój duży plik tekstowy filema ściśle dobrą strukturę (co oznacza, że ​​każda linia ma tę samą długość l), możesz użyć dla n-tego wiersza

with open(file) as f:
    f.seek(n*l)
    line = f.readline() 
    last_pos = f.tell()

Oświadczenie Działa to tylko w przypadku plików o tej samej długości!


2

Co powiesz na to:

>>> with open('a', 'r') as fin: lines = fin.readlines()
>>> for i, line in enumerate(lines):
      if i > 30: break
      if i == 26: dox()
      if i == 30: doy()

To prawda, jest to mniej wydajne niż Alok, ale moje używa instrukcji with;)
Hamish Grubijan,

2

Jeśli nie przeszkadza Ci importowanie, fileinput wykonuje dokładnie to, czego potrzebujesz (możesz odczytać numer bieżącej linii)


2
def getitems(iterable, items):
  items = list(items) # get a list from any iterable and make our own copy
                      # since we modify it
  if items:
    items.sort()
    for n, v in enumerate(iterable):
      if n == items[0]:
        yield v
        items.pop(0)
        if not items:
          break

print list(getitems(open("/usr/share/dict/words"), [25, 29]))
# ['Abelson\n', 'Abernathy\n']
# note that index 25 is the 26th item

Roger, mój ulubiony facet! To może skorzystać z oświadczenia z.
Hamish Grubijan

2

Wolę to podejście, ponieważ jest bardziej ogólne, tzn. Możesz użyć go w pliku, w wyniku f.readlines(), na StringIOobiekcie, cokolwiek:

def read_specific_lines(file, lines_to_read):
   """file is any iterable; lines_to_read is an iterable containing int values"""
   lines = set(lines_to_read)
   last = max(lines)
   for n, line in enumerate(file):
      if n + 1 in lines:
          yield line
      if n + 1 > last:
          return

>>> with open(r'c:\temp\words.txt') as f:
        [s for s in read_specific_lines(f, [1, 2, 3, 1000])]
['A\n', 'a\n', 'aa\n', 'accordant\n']

2

Oto moje małe 2 centy, za ile są warte;)

def indexLines(filename, lines=[2,4,6,8,10,12,3,5,7,1]):
    fp   = open(filename, "r")
    src  = fp.readlines()
    data = [(index, line) for index, line in enumerate(src) if index in lines]
    fp.close()
    return data


# Usage below
filename = "C:\\Your\\Path\\And\\Filename.txt"
for line in indexLines(filename): # using default list, specify your own list of lines otherwise
    print "Line: %s\nData: %s\n" % (line[0], line[1])

2

Lepsza i drobna zmiana w odpowiedzi Aloka Singhala

fp = open("file")
for i, line in enumerate(fp,1):
    if i == 26:
        # 26th line
    elif i == 30:
        # 30th line
    elif i > 30:
        break
fp.close()


1

@OP, możesz użyć wyliczenia

for n,line in enumerate(open("file")):
    if n+1 in [26,30]: # or n in [25,29] 
       print line.rstrip()

1
file = '/path/to/file_to_be_read.txt'
with open(file) as f:
    print f.readlines()[26]
    print f.readlines()[30]

Za pomocą instrukcji with otwiera to plik, drukuje linie 26 i 30, a następnie zamyka plik. Prosty!


to nie jest poprawna odpowiedź. po pierwszym wezwaniu do readlines()iteratora wyczerpie się, a drugie wywołanie zwróci pustą listę lub wyrzuci błąd (nie pamiętam, które)
Paul H

1

Możesz to zrobić bardzo prosto, korzystając ze składni, o której ktoś już wspomniał, ale jest to zdecydowanie najłatwiejszy sposób:

inputFile = open("lineNumbers.txt", "r")
lines = inputFile.readlines()
print (lines[0])
print (lines[2])

1

Aby wydrukować linię nr 3,

line_number = 3

with open(filename,"r") as file:
current_line = 1
for line in file:
    if current_line == line_number:
        print(file.readline())
        break
    current_line += 1

Oryginalny autor: Frank Hofmann


1

Dość szybko i na temat.

Aby wydrukować określone wiersze w pliku tekstowym. Utwórz listę „lines2print”, a następnie po prostu wydrukuj, gdy wyliczenie jest „na” liście lines2print. Aby pozbyć się dodatkowych „\ n”, użyj line.strip () lub line.strip ('\ n'). Po prostu lubię „rozumienie listy” i staram się używać, kiedy mogę. Lubię metodę „with” do czytania plików tekstowych, aby zapobiec pozostawieniu pliku otwartego z jakiegokolwiek powodu.

lines2print = [26,30] # can be a big list and order doesn't matter.

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in lines2print]

lub jeśli lista jest mała, po prostu wpisz listę jako listę do zrozumienia.

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in [26,30]]

0

Aby wydrukować żądaną linię. Aby wydrukować linię powyżej / poniżej wymaganej linii.

def dline(file,no,add_sub=0):
    tf=open(file)
    for sno,line in enumerate(tf):
        if sno==no-1+add_sub:
         print(line)
    tf.close()

wykonaj ----> dline („D: \ dummy.txt”, 6) tj. dline („ścieżka pliku”, numer_wiersza, jeśli chcesz, aby górna linia szukanej linii dawała 1 dla dolnej -1, jest to opcjonalna wartość domyślna będzie być zajęty 0)


0

Jeśli chcesz odczytać określone linie, takie jak linia rozpoczynająca się po pewnej linii progowej, możesz użyć następujących kodów, file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines


-1
f = open(filename, 'r')
totalLines = len(f.readlines())
f.close()
f = open(filename, 'r')

lineno = 1
while lineno < totalLines:
    line = f.readline()

    if lineno == 26:
        doLine26Commmand(line)

    elif lineno == 30:
        doLine30Commmand(line)

    lineno += 1
f.close()

7
jest to tak mało mityczne, jak to możliwe.
SilentGhost,

Daje zły wynik, ponieważ nie można używać linii readline i readline w ten sposób (każda z nich zmienia bieżącą pozycję odczytu).

Przepraszam, że przeoczyłem OGROMNY błąd w moim pierwszym kodzie. Błąd został poprawiony i bieżący kod powinien działać zgodnie z oczekiwaniami. Dzięki za zwrócenie uwagi na mój błąd, Roger Pate.
inspectorG4dget

-1

Myślę, że to zadziała

 open_file1 = open("E:\\test.txt",'r')
 read_it1 = open_file1.read()
 myline1 = []
 for line1 in read_it1.splitlines():
 myline1.append(line1)
 print myline1[0]

Kiedy już to opublikowałeś, było już kilkanaście metod readline - dodanie kolejnej dodaje bałaganu
duhaime
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.