Permintaan adalah perpustakaan yang sangat bagus. Saya ingin menggunakannya untuk mengunduh file besar (> 1GB). Masalahnya adalah itu tidak mungkin untuk menyimpan seluruh file dalam memori saya harus membacanya dalam potongan. Dan ini merupakan masalah dengan kode berikut
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
Dengan beberapa alasan itu tidak berfungsi seperti ini. Itu masih memuat respons ke dalam memori sebelum menyimpannya ke file.
MEMPERBARUI
Jika Anda memerlukan klien kecil (Python 2.x /3.x) yang dapat mengunduh file besar dari FTP, Anda dapat menemukannya di sini . Ini mendukung multithreading & menghubungkan kembali (ini memonitor koneksi) dan juga menyetel params socket untuk tugas pengunduhan.
sumber
chunk_size
sangat penting. secara default 1 (1 byte). itu berarti bahwa untuk 1MB itu akan membuat 1 juta iterasi. docs.python-requests.org/en/latest/api/…f.flush()
sepertinya tidak perlu. Apa yang ingin Anda capai dengan menggunakannya? (Penggunaan memori Anda tidak akan 1,5 GB jika Anda menjatuhkannya).f.write(b'')
(Jikaiter_content()
dapat mengembalikan string kosong) harus tidak berbahaya dan karena ituif chunk
bisa dijatuhkan juga.f.flush()
tidak menyiram data ke disk fisik. Ini mentransfer data ke OS. Biasanya, itu sudah cukup kecuali ada kegagalan daya.f.flush()
membuat kode lebih lambat di sini tanpa alasan. Siram terjadi ketika buffer file correponding (aplikasi dalam) penuh. Jika Anda perlu lebih sering menulis; meneruskan parameter buf.size keopen()
.r.close()
Jauh lebih mudah jika Anda menggunakan
Response.raw
danshutil.copyfileobj()
:Ini mengalirkan file ke disk tanpa menggunakan memori yang berlebihan, dan kodenya sederhana.
sumber
with
blok kedua (bersarang) untuk membuat permintaan:with requests.get(url, stream=True) as r:
with requests.get()
baru digabung pada 2017-06-07! Saran Anda masuk akal untuk orang yang memiliki Permintaan 2.18.0 atau lebih tinggi. Ref: github.com/requests/requests/issues/4136read
metode:response.raw.read = functools.partial(response.raw.read, decode_content=True)
Tidak persis dengan apa yang diminta OP, tapi ... sangat mudah untuk melakukannya dengan
urllib
:Atau dengan cara ini, jika Anda ingin menyimpannya ke file sementara:
Saya menyaksikan prosesnya:
Dan saya melihat file tumbuh, tetapi penggunaan memori tetap di 17 MB. Apakah saya melewatkan sesuatu?
sumber
from urllib import urlretrieve
shutil.copyfileobj
dengan suara terbanyak, lihat komentar saya dan orang lain di sanaUkuran chunk Anda mungkin terlalu besar, sudahkah Anda mencoba menjatuhkannya - mungkin 1024 byte sekaligus? (juga, Anda bisa menggunakan
with
untuk merapikan sintaks)Kebetulan, bagaimana Anda menyimpulkan bahwa respons telah dimuat ke memori?
Kedengarannya seolah-olah python tidak membuang data ke file, dari pertanyaan SO lainnya Anda bisa mencoba
f.flush()
danos.fsync()
memaksa file menulis dan membebaskan memori;sumber
f.flush(); os.fsync()
bisa memaksa menulis memori bebas.os.fsync(f.fileno())
def DownloadFile(url)