Jak czytać duży plik - linia po linii?


536

Chcę iterować po każdej linii całego pliku. Jednym ze sposobów na to jest czytanie całego pliku, zapisywanie go na liście, a następnie przekraczanie linii zainteresowania. Ta metoda zużywa dużo pamięci, więc szukam alternatywy.

Mój kod do tej pory:

for each_line in fileinput.input(input_file):
    do_something(each_line)

    for each_line_again in fileinput.input(input_file):
        do_something(each_line_again)

Wykonanie tego kodu daje komunikat o błędzie: device active.

Jakieś sugestie?

Celem jest obliczenie podobieństwa ciągów parami, co oznacza, że ​​dla każdej linii w pliku chcę obliczyć odległość Levenshteina z każdą inną linią.


4
Dlaczego musisz ponownie przeczytać cały plik dla każdej linii? Może gdybyś powiedział, co próbujesz osiągnąć, ktoś może zaproponować lepsze podejście.
JJJ,

Odpowiedzi:


1269

Prawidłowy, w pełni Pythoński sposób odczytu pliku jest następujący:

with open(...) as f:
    for line in f:
        # Do something with 'line'

Te withuchwyty komunikat otwierania i zamykania pliku, w tym, jeśli jest wyjątek w wewnętrznym bloku. Do for line in ftraktuje obiekt File fjako iterable, który wykorzystuje automatycznie buforowane I / O i zarządzanie pamięcią, dzięki czemu nie trzeba się martwić o dużych plików.

Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.


14
tak, jest to najlepsza wersja z Pythonem 2.6 i nowszym
Simon Bergot

3
Osobiście wolę generatory i korporacje do obsługi potoków danych.
jldupont

4
jaka byłaby najlepsza strategia, jeśli plik jest dużym plikiem tekstowym, ale z jednym wierszem, a pomysł polega na przetwarzaniu słów?
mfcabrera,

4
Czy ktoś mógłby wyjaśnić, jak for line in f:działa? Mam na myśli, w jaki sposób możliwe jest iterowanie obiektu pliku?
haccks,

11
Jeśli wykonujesz iterację nad obiektem, Python sprawdza na liście metod obiektowych specjalną metodę o nazwie __iter__, która mówi mu, co robić. Obiekty plików definiują tę specjalną metodę zwracania iteratora po wierszach. (Z grubsza.)
Katriel

130

Dwa sposoby oszczędzania pamięci w kolejności uszeregowanej (pierwszy jest najlepszy) -

  1. use with- obsługiwane z Python 2.5 i nowszych
  2. użyj, yieldjeśli naprawdę chcesz mieć kontrolę nad tym, ile czytać

1. użycie with

withjest dobrym i wydajnym pythonowym sposobem czytania dużych plików. zalety - 1) obiekt pliku jest automatycznie zamykany po wyjściu z withbloku wykonawczego. 2) obsługa wyjątków wewnątrz withbloku. 3) forPętla pamięci przechodzi przez fobiekt obiektu linia po linii. wewnętrznie buforuje operacje we / wy (zoptymalizowane pod kątem kosztownych operacji we / wy) i zarządzanie pamięcią.

with open("x.txt") as f:
    for line in f:
        do something with data

2. użycie yield

Czasami ktoś może chcieć dokładniejszej kontroli nad tym, ile czytać w każdej iteracji. W takim wypadku należy iter i wydajnością . Uwaga: w przypadku tej metody należy wyraźnie zamknąć plik na końcu.

def readInChunks(fileObj, chunkSize=2048):
    """
    Lazy function to read a file piece by piece.
    Default chunk size: 2kB.
    """
    while True:
        data = fileObj.read(chunkSize)
        if not data:
            break
        yield data

f = open('bigFile')
for chuck in readInChunks(f):
    do_something(chunk)
f.close()

Pułapki i ze względu na kompletność - poniższe metody nie są tak dobre lub nie tak eleganckie do czytania dużych plików, ale proszę przeczytać, aby uzyskać ogólne zrozumienie.

W Pythonie najczęstszym sposobem odczytywania wierszy z pliku jest wykonanie następujących czynności:

for line in open('myfile','r').readlines():
    do_something(line)

Kiedy to się jednak stanie, readlines()funkcja (to samo dotyczy read()funkcji) ładuje cały plik do pamięci, a następnie wykonuje iterację. Nieco lepsze podejście (pierwsze dwie wspomniane metody są najlepsze) dla dużych plików to użycie fileinputmodułu w następujący sposób:

import fileinput

for line in fileinput.input(['myfile']):
    do_something(line)

fileinput.input()wezwanie czyta wiersze kolejno, ale nie przechowuje je w pamięci po ich czytać, a nawet po prostu tak to, ponieważ filew Pythonie jest iterable.

Bibliografia

  1. Python z instrukcją

9
-1 Zasadniczo nigdy nie jest dobrym pomysłem for line in open(...).readlines(): <do stuff>. Dlaczego miałbyś?! Właśnie straciłeś wszystkie zalety sprytnego IO buforowanego iteratora Pythona bez żadnej korzyści.
Katriel

5
@ Srikar: jest czas i miejsce na podanie wszystkich możliwych rozwiązań problemu; nauczanie początkującego, jak wprowadzać pliki, to nie to. Umieszczenie prawidłowej odpowiedzi na dole długiego postu pełnego błędnych odpowiedzi nie jest dobrym nauczaniem.
Katriel,

6
@ Srikar: Możesz znacznie poprawić swój post, umieszczając właściwą drogę u góry, a następnie wspominając readlinesi wyjaśniając, dlaczego nie jest to dobra rzecz (ponieważ odczytuje plik do pamięci), a następnie wyjaśniając, co fileinputrobi moduł i dlaczego może chcieć użyć go w porównaniu z innymi metodami, a następnie wyjaśnić, w jaki sposób dzielenie pliku poprawia IO i podać przykład funkcji dzielenia (ale wspominając, że Python robi to już za ciebie, więc nie musisz). Ale podanie pięciu sposobów rozwiązania prostego problemu, z których cztery są w tym przypadku błędne, nie jest dobre.
Katriel,

2
Cokolwiek dodasz w celu uzupełnienia, dodaj to na końcu, a nie na początku. Najpierw pokaż właściwą drogę.
m000

6
@katrielalex ponownie przejrzał moją odpowiedź i stwierdził, że uzasadnia to restrukturyzację. Widzę, jak wcześniejsza odpowiedź może powodować zamieszanie. Mamy nadzieję, że dzięki temu będzie to jasne dla przyszłych użytkowników.
Srikar Appalaraju,

37

Aby usunąć nowe linie:

with open(file_path, 'rU') as f:
    for line_terminated in f:
        line = line_terminated.rstrip('\n')
        ...

Z powszechnego poparcia nowej linii wszystkie linie pliku tekstowego będzie wydają się być zakończona '\n', co terminatory w pliku '\r', '\n'lub '\r\n'.

EDYCJA - Aby określić uniwersalną obsługę nowej linii:

  • Python 2 w systemie Unix - open(file_path, mode='rU')- wymagany [dzięki @Dave ]
  • Python 2 w systemie Windows - open(file_path, mode='rU')- opcjonalny
  • Python 3 - open(file_path, newline=None)- opcjonalny

Ten newlineparametr jest obsługiwany tylko w Pythonie 3 i domyślnie jest ustawiony na None. W modedomyślnie parametr, aby 'r'we wszystkich przypadkach. UJest przestarzałe w Pythonie 3. W Pythonie 2 na Windows jakiś inny mechanizm wydaje się przekładać \r\nna \n.

Dokumenty:

Aby zachować terminatory linii rodzimej:

with open(file_path, 'rb') as f:
    with line_native_terminated in f:
        ...

Tryb binarny może nadal przetwarzać plik na linie z in. Każda linia będzie zawierała dowolne terminatory w pliku.

Dzięki @katrielalex „s odpowiedź , Pythona open () doc i ipython eksperymentów.


1
W Pythonie 2.7 musiałem open(file_path, 'rU')włączyć uniwersalne znaki nowej linii.
Dave

17

jest to możliwy sposób odczytu pliku w pythonie:

f = open(input_file)
for line in f:
    do_stuff(line)
f.close()

nie przydziela pełnej listy. Iteruje po liniach.


2
Chociaż to działa, zdecydowanie nie jest to kanoniczny sposób. Kanonicznym sposobem jest użycie opakowania kontekstowego, takiego jak with open(input_file) as f:. To oszczędza f.close()i zapewnia, że ​​nie zapomnisz przypadkowo go zamknąć. Zapobiega wyciekom pamięci i wszystkim, co jest bardzo ważne podczas odczytu plików.
Maszt

1
Jak powiedział @Mast, nie jest to kanoniczny sposób, dlatego głosujcie za tym.
azuax

12

Pewien kontekst z góry, skąd pochodzę. Fragmenty kodu znajdują się na końcu.

Kiedy mogę, wolę używać narzędzia typu open source, takiego jak H2O, do robienia bardzo wysokiej wydajności równoległych odczytów plików CSV, ale to narzędzie ma ograniczony zestaw funkcji. W końcu piszę dużo kodu do tworzenia potoków nauki danych przed przekazaniem do klastra H2O w celu właściwego nadzorowanego uczenia się.

Czytam pliki takie jak 8 GB zestawu danych HIGGS z repozytorium UCI, a nawet 40 GB plików CSV do celów analizy danych znacznie szybciej, dodając dużo równoległości z obiektem puli i funkcją mapy biblioteki wieloprocesowej. Na przykład grupowanie z wyszukiwaniem najbliższych sąsiadów, a także algorytmy klastrowania DBSCAN i Markowa wymagają pewnej finezji programowania równoległego, aby ominąć niektóre poważnie trudne problemy z pamięcią i czasem zegara ściennego.

Zwykle lubię łamać plik wierszowo na części za pomocą narzędzi GNU, a następnie glob-filemaskować je wszystkie, aby znaleźć i odczytać je równolegle w programie python. Często używam ponad 1000 plików częściowych. Wykonanie tych sztuczek niezwykle pomaga w ograniczeniu prędkości przetwarzania i pamięci.

Panda dataframe.read_csv jest jednowątkowa, więc możesz wykonywać te sztuczki, aby pandy były znacznie szybsze, uruchamiając map () do równoległego wykonywania. Możesz użyć htop, aby zobaczyć, że przy zwykłych starych sekwencyjnych pandach dataframe.read_csv, 100% procesora na tylko jednym rdzeniu stanowi rzeczywiste wąskie gardło w pd.read_csv, a nie dysk.

Powinienem dodać, że używam dysku SSD na szybkiej magistrali karty graficznej, a nie obracającego się HD na szynie SATA6 oraz 16 rdzeni procesora.

Ponadto inną techniką, którą odkryłem, że działa świetnie w niektórych aplikacjach, jest równoległe odczytywanie pliku CSV w jednym gigantycznym pliku, rozpoczynanie każdego procesu roboczego z innym przesunięciem do pliku, zamiast wstępnego dzielenia jednego dużego pliku na wiele plików części. Użyj metody seek () i tell () pythona w każdym równoległym procesie roboczym, aby odczytać duży plik tekstowy w paskach, w różnych bajtach z przesunięciem bajtów w lokalizacjach początkowych i końcowych bajtów jednocześnie, jednocześnie. Możesz zrobić wyrażenie regularne na bajtach i zwrócić liczbę kanałów. To jest suma częściowa. Na koniec zsumuj sumy częściowe, aby uzyskać sumę globalną, gdy funkcja mapy powróci po zakończeniu procesu roboczego.

Oto kilka przykładowych testów porównawczych z wykorzystaniem sztuczki polegającej na przesunięciu bajtów równoległych:

Używam 2 plików: HIGGS.csv ma ​​8 GB. Pochodzi z repozytorium uczenia maszynowego UCI. all_bin .csv ma ​​40,4 GB i pochodzi z mojego obecnego projektu. Używam 2 programów: programu wc GNU, który jest dostarczany z Linuksem, i opracowanego przeze mnie czystego programu pytread fastread.py.

HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv

HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb  2 09:00 all_bin.csv

ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496

real    0m8.920s
user    1m30.056s
sys 2m38.744s

In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175

To około 4,5 GB / s, czyli 45 Gb / s, prędkość usuwania plików. To nie jest wirujący dysk twardy, przyjacielu. To właściwie dysk SSD Samsung Pro 950.

Poniżej znajduje się test porównawczy prędkości dla tego samego pliku liczonego w linii przez gnu wc, program skompilowany w czystym C.

Fajne jest to, że w tym przypadku mój czysty program w Pythonie zasadniczo pasował do prędkości skompilowanego programu C w GNU WC. Python jest interpretowany, ale C jest kompilowany, więc jest to dość interesujący wyczyn prędkości, myślę, że się zgodzisz. Oczywiście wc naprawdę trzeba zmienić na program równoległy, a wtedy naprawdę pobiłbym skarpety mojego programu python. Ale w obecnej formie gnu wc to tylko program sekwencyjny. Robisz, co możesz, a Python może dziś robić równolegle. Kompilacja Cython może mi pomóc (przez jakiś czas). Również pliki mapowane w pamięci nie zostały jeszcze zbadane.

HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv

real    0m8.807s
user    0m1.168s
sys 0m7.636s


HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.257s
user    0m12.088s
sys 0m20.512s

HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv

real    0m1.820s
user    0m0.364s
sys 0m1.456s

Wniosek: Szybkość jest dobra dla czystego programu python w porównaniu do programu C. Jednak nie wystarczy używać czystego programu pythonowego nad programem C, przynajmniej do celów zliczania linii. Ogólnie technika ta może być używana do innego przetwarzania plików, więc ten kod Pythona jest nadal dobry.

Pytanie: Czy skompilowanie wyrażenia regularnego tylko raz i przekazanie go wszystkim pracownikom poprawi szybkość? Odpowiedź: Kompilacja wstępna Regex NIE pomaga w tej aplikacji. Podejrzewam, że powodem jest to, że dominują koszty związane z serializacją i tworzeniem procesów dla wszystkich pracowników.

Jeszcze jedna rzecz. Czy równoległe czytanie plików CSV w ogóle pomaga? Czy dysk jest wąskim gardłem, czy jest to procesor? Wiele tak zwanych najwyżej ocenianych odpowiedzi na stackoverflow zawiera powszechną mądrość programistyczną, że do odczytania pliku potrzebny jest tylko jeden wątek, najlepiej, jak można, mówią. Czy są jednak pewni?

Dowiedzmy Się:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.256s
user    0m10.696s
sys 0m19.952s

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000

real    0m17.380s
user    0m11.124s
sys 0m6.272s

O tak, tak. Równoległe czytanie plików działa całkiem dobrze. Cóż, proszę bardzo!

Ps. W przypadku, gdyby niektórzy z was chcieli wiedzieć, co by było, gdyby balanceFactor wynosił 2 podczas korzystania z jednego procesu roboczego? Cóż, to okropne:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000

real    1m37.077s
user    0m12.432s
sys 1m24.700s

Kluczowe części programu python fastread.py:

fileBytes = stat(fileName).st_size  # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)


def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'):  # counts number of searchChar appearing in the byte range
    with open(fileName, 'r') as f:
        f.seek(startByte-1)  # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
        bytes = f.read(endByte - startByte + 1)
        cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
    return cnt

Def dla PartitionDataToWorkers to zwykły sekwencyjny kod. Zostawiłem to na wypadek, gdyby ktoś chciał poćwiczyć na programowaniu równoległym. Oddałem za darmo trudniejsze części: przetestowany i działający kod równoległy, dla twojej korzyści w nauce.

Dzięki: Projekt H2O typu open source autorstwa Arno i Cliffa oraz pracowników H2O za ich wspaniałe oprogramowanie i filmy instruktażowe, które dały mi inspirację do tego czysto pythonowego, równoległego czytnika offsetów bajtowych, jak pokazano powyżej. H2O dokonuje równoległego odczytu plików przy użyciu java, jest wywoływalny przez programy Python i R, i jest szalony szybki, szybszy niż cokolwiek na świecie przy czytaniu dużych plików CSV.


Zasadniczo są to porcje równoległe. Ponadto oczekuję, że dyski SSD i Flash są jedynymi kompatybilnymi urządzeniami pamięci masowej z tą techniką. Spinning HD raczej nie będzie kompatybilny.
Geoffrey Anderson

1
Jak uwzględniłeś pliki pamięci podręcznej systemu operacyjnego?
JamesThomasMoon1979

5

Katrielalex zapewnił sposób na otwarcie i odczytanie jednego pliku.

Jednak sposób, w jaki podąża Twój algorytm, odczytuje cały plik dla każdej linii pliku. Oznacza to, że całkowity odczyt pliku - i obliczenie odległości Levenshteina - zostanie wykonane N * N, jeśli N jest liczbą linii w pliku. Ponieważ martwisz się rozmiarem pliku i nie chcesz zachować go w pamięci, martwię się o wynikowy kwadratowy czas działania . Twój algorytm należy do klasy algorytmów O (n ^ 2), które często można ulepszyć dzięki specjalizacji.

Podejrzewam, że znasz już kompromis między pamięcią a środowiskiem uruchomieniowym, ale być może chciałbyś sprawdzić, czy istnieje skuteczny sposób na obliczenie wielu odległości Levenshteina równolegle. Jeśli tak, warto podzielić się tutaj swoim rozwiązaniem.

Ile linii mają twoje pliki i na jakim komputerze (mem i CPU) musi działać twój algorytm i jaki jest tolerowany czas działania?

Kod wyglądałby następująco:

with f_outer as open(input_file, 'r'):
    for line_outer in f_outer:
        with f_inner as open(input_file, 'r'):
            for line_inner in f_inner:
                compute_distance(line_outer, line_inner)

Ale pytania dotyczą sposobu przechowywania odległości (macierzy?) I czy można uzyskać przewagę, przygotowując np. Linię_zewnętrzną do przetwarzania lub buforując niektóre wyniki pośrednie do ponownego wykorzystania.


Chodzi mi o to, że ten post nie zawiera odpowiedzi na pytanie, tylko kilka pytań! IMO lepiej by to pasowało jako komentarz.
Katriel

1
@katriealex: Err. Dziwne. Widziałeś zagnieżdżone pętle, rozszerzając własną odpowiedź, aby pasowała do rzeczywistego pytania? Mogę usunąć moje pytania tutaj z mojej odpowiedzi, a jest jeszcze wystarczająco dużo treści, aby uzasadnić udzielenie tego - choć częściowo - odpowiedzi. Mogę również zaakceptować, jeśli zredagujesz własną odpowiedź, aby uwzględnić przykład zagnieżdżonej pętli - o co wyraźnie pytało pytanie - a następnie z radością usunę własną odpowiedź. Ale opinia negatywna to coś, czego w ogóle nie rozumiem.
cfi

Słusznie; Tak naprawdę nie widzę pokazywania zagnieżdżonej pętli jako odpowiedzi na pytanie, ale wydaje mi się, że jest dość silnie ukierunkowana na początkujących. Usunięto głosowanie.
Katriel

3
#Using a text file for the example
with open("yourFile.txt","r") as f:
    text = f.readlines()
for line in text:
    print line
  • Otwórz plik do czytania (r)
  • Przeczytaj cały plik i zapisz każdą linię na liście (tekst)
  • Zapętlaj listę, drukując każdą linię.

Jeśli chcesz na przykład sprawdzić określoną linię dla długości większej niż 10, pracuj z tym, co już masz dostępne.

for line in text:
    if len(line) > 10:
        print line

1
Nie jest to najlepsze w przypadku tego pytania, ale ten kod jest przydatny głównie w przypadku, gdy szukasz. To „slurowanie” (odczytywanie całego pliku na raz). To był mój przypadek i Google mnie tu sprowadził. +1. Ponadto, jeśli chodzi o atomowość lub jeśli czasochłonne przetwarzanie w pętli może skończyć się szybciej, aby odczytać cały plik
ntg

1
Poprawiono także nieco kod: 1. zamknięcie nie jest potrzebne po: ( docs.python.org/2/tutorial/inputoutput.html , wyszukaj „Dobrą praktyką jest używanie słowa kluczowego ...”) 2 . tekst może być przetwarzany po odczytaniu pliku (poza pętlą ....)
ntg

2

Z dokumentacji Pythona dla fileinput .input ():

Powoduje to iterację po wierszach wszystkich plików wymienionych w sys.argv[1:], domyślnie sys.stdinjeśli lista jest pusta

ponadto definicją tej funkcji jest:

fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])

czytając między wierszami, to mówi mi, że filesmoże to być lista, więc możesz mieć coś takiego:

for each_line in fileinput.input([input_file, input_file]):
  do_something(each_line)

Zobacz tutaj, aby uzyskać więcej informacji


2

Zdecydowanie odradzam używanie domyślnego ładowania plików, ponieważ jest on strasznie powolny. Powinieneś przyjrzeć się funkcjom numpy i IOpro (np. Numpy.loadtxt ()).

http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

https://store.continuum.io/cshop/iopro/

Następnie możesz podzielić operację parowania na części:

import numpy as np
import math

lines_total = n    
similarity = np.zeros(n,n)
lines_per_chunk = m
n_chunks = math.ceil(float(n)/m)
for i in xrange(n_chunks):
    for j in xrange(n_chunks):
        chunk_i = (function of your choice to read lines i*lines_per_chunk to (i+1)*lines_per_chunk)
        chunk_j = (function of your choice to read lines j*lines_per_chunk to (j+1)*lines_per_chunk)
        similarity[i*lines_per_chunk:(i+1)*lines_per_chunk,
                   j*lines_per_chunk:(j+1)*lines_per_chunk] = fast_operation(chunk_i, chunk_j) 

Prawie zawsze jest o wiele szybsze ładowanie danych w porcjach, a następnie wykonywanie na nich operacji macierzowych, niż robienie tego element po elemencie !!


0

Chcesz często czytać duży plik z ostatniego odczytu pozycji?

Stworzyłem skrypt używany do wycinania pliku access.log Apache kilka razy dziennie. Musiałem więc ustawić kursor pozycji na ostatniej linii parsowanej podczas ostatniego wykonania . W tym celu użyłem file.seek()ifile.seek() metody, które pozwala na przechowywanie kursora w pliku.

Mój kod:

ENCODING = "utf8"
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))

# This file is used to store the last cursor position
cursor_position = os.path.join(CURRENT_FILE_DIR, "access_cursor_position.log")

# Log file with new lines
log_file_to_cut = os.path.join(CURRENT_FILE_DIR, "access.log")
cut_file = os.path.join(CURRENT_FILE_DIR, "cut_access", "cut.log")

# Set in from_line 
from_position = 0
try:
    with open(cursor_position, "r", encoding=ENCODING) as f:
        from_position = int(f.read())
except Exception as e:
    pass

# We read log_file_to_cut to put new lines in cut_file
with open(log_file_to_cut, "r", encoding=ENCODING) as f:
    with open(cut_file, "w", encoding=ENCODING) as fw:
        # We set cursor to the last position used (during last run of script)
        f.seek(from_position)
        for line in f:
            fw.write("%s" % (line))

    # We save the last position of cursor for next usage
    with open(cursor_position, "w", encoding=ENCODING) as fw:
        fw.write(str(f.tell()))

-2

Najlepszym sposobem na odczytanie dużego pliku, wiersz po wierszu, jest użycie funkcji wyliczającej w języku Python

with open(file_name, "rU") as read_file:
    for i, row in enumerate(read_file, 1):
        #do something
        #i in line of that line
        #row containts all data of that line

3
Dlaczego używanie wyliczania jest lepsze? Jedyną zaletą w stosunku do przyjętej odpowiedzi jest to, że otrzymujesz indeks, którego OP nie potrzebuje i sprawia, że ​​kod jest mniej czytelny.
fuyas
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.