Aby napisać leniwą funkcję, po prostu użyj yield
:
def read_in_chunks(file_object, chunk_size=1024):
"""Lazy function (generator) to read a file piece by piece.
Default chunk size: 1k."""
while True:
data = file_object.read(chunk_size)
if not data:
break
yield data
with open('really_big_file.dat') as f:
for piece in read_in_chunks(f):
process_data(piece)
Inną opcją byłoby użycie iter
funkcji pomocniczej:
f = open('really_big_file.dat')
def read1k():
return f.read(1024)
for piece in iter(read1k, ''):
process_data(piece)
Jeśli plik jest oparty na liniach, obiekt pliku jest już leniwym generatorem linii:
for line in open('really_big_file.dat'):
process_data(line)
f = open('really_big_file.dat')
jest tylko wskaźnikiem bez zużycia pamięci? (Mam na myśli, że zużyta pamięć jest taka sama bez względu na rozmiar pliku?) Jak wpłynie to na wydajność, jeśli użyję urllib.readline () zamiast f.readline ()?rb
jak wspomniał @Tal Weiss; i brakfile.close()
oświadczenia (może posłużyćwith open('really_big_file.dat', 'rb') as f:
do osiągnięcia tego samego; zobacz tutaj, aby uzyskać inne zwięzłe wdrożenie'rb'
jest nie brakuje.'b'
jego dane będą bardzo prawdopodobnie uszkodzony . Z dokumentów -Python on Windows makes a distinction between text and binary files; [...] it’ll corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files.
Jeśli twój komputer, system operacyjny i python są 64-bitowe , możesz użyć modułu mmap, aby zmapować zawartość pliku do pamięci i uzyskać do niego dostęp za pomocą indeksów i plasterków. Oto przykład z dokumentacji:
Jeśli komputer, system operacyjny lub python są 32-bitowe , mapowanie dużych plików może zarezerwować duże części przestrzeni adresowej i zagłodzić program pamięci.
źródło
file.readlines()
przyjmuje opcjonalny argument wielkości, który jest zbliżony do liczby linii odczytanych w zwracanych liniach.źródło
.read()
nie używać.readlines()
. Jeśli plik jest binarny, nie będzie miał podziałów linii.Istnieje już wiele dobrych odpowiedzi, ale jeśli cały plik znajduje się w jednej linii i nadal chcesz przetwarzać „wiersze” (w przeciwieństwie do bloków o stałym rozmiarze), te odpowiedzi ci nie pomogą.
W 99% przypadków możliwe jest przetwarzanie plików linia po linii. Następnie, zgodnie z sugestią zawartą w tej odpowiedzi , możesz użyć samego obiektu pliku jako leniwego generatora:
Jednak kiedyś natknąłem się na bardzo duży (prawie) plik jednowierszowy, w którym separator wierszy był w rzeczywistości nie,
'\n'
ale'|'
.'|'
do'\n'
przed przetwarzaniem również nie wchodziła w rachubę, ponieważ niektóre pola tego'\n'
pliku csv zawierały (dowolny tekst wprowadzany przez użytkownika).W takich sytuacjach utworzyłem następujący fragment:
Udało mi się to z powodzeniem wykorzystać do rozwiązania mojego problemu. Został gruntownie przetestowany, z różnymi wielkościami porcji.
Zestaw testowy dla tych, którzy chcą się przekonać.
źródło
AKTUALIZACJA: Podejście to najlepiej wyjaśniono w https://stackoverflow.com/a/4566523/38592
źródło
Zapoznaj się z oficjalną dokumentacją pythona https://docs.python.org/zh-cn/3/library/functions.html?#iter
Może ta metoda jest bardziej pythonowa:
źródło
Myślę, że możemy napisać w ten sposób:
źródło
nie wolno mi komentować z powodu mojej niskiej reputacji, ale rozwiązanie SilentGhosts powinno być znacznie łatwiejsze dzięki file.readlines ([sizehint])
metody plików python
edycja: SilentGhost ma rację, ale powinno to być lepsze niż:
źródło
Jestem w nieco podobnej sytuacji. Nie jest jasne, czy znasz wielkość porcji w bajtach; Zwykle nie, ale liczba wymaganych rekordów (wierszy) jest znana:
Aktualizacja : Dzięki nosklo. Oto co miałem na myśli. Prawie działa, z tym wyjątkiem, że traci linię „między” kawałkami.
Trik bez utraty linii, ale nie wygląda ładnie.
źródło
To eleganckie rozwiązanie do przetwarzania linia po linii:
Dopóki nie ma pustych linii.
źródło
open
już daje. Plik jest już iteratorem ponad swoimi liniami.możesz użyć następującego kodu.
open () zwraca obiekt pliku
następnie użyj os.stat, aby uzyskać rozmiar
źródło