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.