2013-06-12 5 views
7

Chciałbym zrozumieć różnicę w użyciu pamięci RAM tej metody podczas odczytu dużego pliku w pythonie.Odczytuj plik w porcjach - użycie pamięci RAM, przeczytaj ciągi znaków z plików binarnych

Wersja 1, tutaj na stackoverflow:

def read_in_chunks(file_object, chunk_size=1024): 
    while True: 
     data = file_object.read(chunk_size) 
     if not data: 
      break 
     yield data 


f = open(file, 'rb') 
for piece in read_in_chunks(f): 
    process_data(piece)   
f.close() 

Version 2, użyłem tego wcześniej znalazłem powyższy kod:

f = open(file, 'rb') 
while True: 
    piece = f.read(1024)  
    process_data(piece)   
f.close() 

Plik jest częściowo odczytać w obu wersjach. I obecny kawałek może być przetwarzany. W drugim przykładzie, piece uzyskuje nową zawartość w każdym cyklu, więc myślałem, że to będzie działało na nie załadować kompletny plik do pamięci ..?

Ale tak naprawdę nie rozumiem, co robi yield i jestem prawie pewien, że coś tu jest nie tak. Czy ktoś mógłby mi to wyjaśnić?


Jest jeszcze coś, co mnie zastanawia, oprócz od zastosowanej metody:

Zawartość sztukę czytałem jest zdefiniowany przez fragmentu wielkości, 1KB w powyższych przykładach. Ale ... co jeśli potrzebuję szukać ciągów w pliku? Coś takiego jak "ThisIsTheStringILikeToFind"?

W zależności od tego, w którym miejscu pliku występuje ciąg, może to oznaczać, że jedna część zawiera część "ThisIsTheStr" - a następny element będzie zawierał "ingILikeToFind". Przy użyciu takiej metody nie można wykryć całego ciągu w jakimkolwiek utworze.

Czy istnieje sposób, aby odczytać plik w kawałkach - ale jakoś dbać o takie ciągi?

Każda pomoc lub pomysł jest mile widziany,

wita!

+0

można napisać pierwszego fragmentu jako 'dla kawałka w ITER (częściowe (f.read, chunk_size), B„”) : process_data (chunk) '(przyjmij tryb binarny). Odpowiedź na ostatnie pytanie brzmi: tak: po prostu sprawdź, czy porcja kończy się prefiksem łańcucha, a następny fragment zaczyna się od odpowiedniego sufiksu. – jfs

+0

Dziękuję, że wspomniałeś o 'iter' - tego nie wiedziałeś! Drugie pytanie: Masz na myśli, że mogę sprawdzić, czy utwór kończy się na 'T' lub' Th' lub 'Thi' lub' This' - i tak dalej? Hmm, fajny pomysł! Dzięki! – xph

Odpowiedz

15

yield to słowo kluczowe w pythonie używane do wyrażeń generatora. Oznacza to, że przy następnym wywołaniu funkcji (lub iteracji) wykonanie uruchomi się ponownie w punkcie, w którym zostało przerwane po ostatnim wywołaniu tej funkcji. Obie funkcje działają identycznie; jedyną różnicą jest to, że pierwsza używa odrobinę więcej przestrzeni stosu wywołań niż druga. Jednak pierwszy z nich jest znacznie bardziej przydatny do ponownego wykorzystania, więc z punktu widzenia projektu programu, pierwszy jest w rzeczywistości lepszy.

EDYCJA: Inną różnicą jest to, że pierwsza zatrzyma czytanie po odczytaniu wszystkich danych, tak jak powinna, ale druga zatrzyma się, gdy f.read() lub process_data() zgłasza wyjątek. W celu uzyskania drugiego działa prawidłowo, trzeba go zmodyfikować tak:

f = open(file, 'rb') 
while True: 
    piece = f.read(1024) 
    if not piece: 
     break 
    process_data(piece) 
f.close() 
+0

Dziękujemy za odpowiedź! Rozumiem, że pierwsza wersja jest lepsza do wielokrotnego użytku, definiuje funkcję, która może być przydatna również w innych projektach. Wydaje się, że większe "miejsce na stos połączeń" wynika z tego? Tworzenie funkcji?Ale nie ma różnicy w użyciu pamięci RAM samego pliku? Znalazłem trochę dokumentacji o funkcjach generatora, nie jest to łatwe do zrozumienia, kiedy masz cały czas pod ręką wspólne funkcje - ale jeśli mam to prawo, pierwsza wersja "zwróci" tylko pierwszy fragment pliku a pętla 'for' będzie cyklicznie przechodzić przez dane' piece', bez 'yield'? – xph

+0

Jeśli podoba Ci się moja odpowiedź, czy możesz oznaczyć ją jako zaakceptowaną odpowiedź? (faktycznie dostajesz 2 powtórzenia za to) – AJMansfield

+0

Och, tak! Oczywiście, przepraszam ... :-) – xph