Requests to naprawdę fajna biblioteka. Chciałbym go użyć do pobierania dużych plików (> 1 GB). Problem polega na tym, że nie można zachować całego pliku w pamięci. Potrzebuję go odczytać w kawałkach. Jest to problem z następującym kodem
import requests
def DownloadFile(url)
local_filename = url.split('/')[-1]
r = requests.get(url)
f = open(local_filename, 'wb')
for chunk in r.iter_content(chunk_size=512 * 1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.close()
return
Z jakiegoś powodu to nie działa w ten sposób. Nadal ładuje odpowiedź do pamięci przed zapisaniem jej w pliku.
AKTUALIZACJA
Jeśli potrzebujesz małego klienta (Python 2.x / 3..x), który może pobierać duże pliki z FTP, możesz go znaleźć tutaj . Obsługuje wielowątkowość i ponowne łączenie (monitoruje połączenia), a także dostraja parametry gniazd dla zadania pobierania.
źródło
chunk_size
jest kluczowe. domyślnie jest to 1 (1 bajt). oznacza to, że za 1 MB wykona 1 milion iteracji. docs.python-requests.org/en/latest/api/…f.flush()
wydaje się niepotrzebne. Co próbujesz osiągnąć, używając go? (użycie pamięci nie wyniesie 1,5 GB, jeśli ją upuścisz).f.write(b'')
(jeśliiter_content()
może zwrócić pusty ciąg) powinien być nieszkodliwy i dlategoif chunk
może zostać upuszczony.f.flush()
nie opróżnia danych na dysk fizyczny. Przesyła dane do systemu operacyjnego. Zwykle wystarczy, chyba że nastąpi awaria zasilania.f.flush()
spowalnia kod tutaj bez powodu. Opróżnianie ma miejsce, gdy odpowiedni bufor pliku (w aplikacji) jest pełny. Jeśli potrzebujesz częstszych zapisów; przekazać parametr buf.size doopen()
.r.close()
Jest to o wiele łatwiejsze, jeśli używasz
Response.raw
ishutil.copyfileobj()
:To przesyła plik na dysk bez użycia nadmiernej pamięci, a kod jest prosty.
źródło
with
bloku, aby wysłać żądanie:with requests.get(url, stream=True) as r:
with requests.get()
została połączona dopiero w dniu 2017-06-07! Twoja sugestia jest uzasadniona dla osób, które mają Wnioski 2.18.0 lub nowsze. Ref: github.com/requests/requests/issues/4136read
metodę:response.raw.read = functools.partial(response.raw.read, decode_content=True)
Nie do końca to, o co prosi OP, ale ... jest to absurdalnie łatwe, aby to zrobić za pomocą
urllib
:Lub w ten sposób, jeśli chcesz zapisać go do pliku tymczasowego:
Obejrzałem proces:
Widziałem, jak plik się powiększa, ale zużycie pamięci pozostało na poziomie 17 MB. Czy coś brakuje?
źródło
from urllib import urlretrieve
shutil.copyfileobj
z największą liczbą głosów, zobacz moje i inne komentarze tamTwój rozmiar fragmentu może być zbyt duży, czy próbowałeś to upuścić - może 1024 bajty na raz? (możesz też użyć
with
do uporządkowania składni)Nawiasem mówiąc, jak wnioskujesz, że odpowiedź została załadowana do pamięci?
To brzmi tak, jakby pyton nie jest przepłukanie danych do pliku, od innych pytań, dlatego można spróbować
f.flush()
ios.fsync()
aby wymusić zapis pliku i wolnej pamięci;źródło
f.flush(); os.fsync()
może wymusić zapisanie pamięci wolnej.os.fsync(f.fileno())
def DownloadFile(url)