Requests est une bibliothèque vraiment sympa. Je voudrais l'utiliser pour télécharger de gros fichiers (> 1 Go). Le problème est qu'il n'est pas possible de conserver le fichier entier en mémoire, j'ai besoin de le lire en morceaux. Et c'est un problème avec le code suivant
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
Pour une raison quelconque, cela ne fonctionne pas de cette façon. Il charge toujours la réponse en mémoire avant de l'enregistrer dans un fichier.
MISE À JOUR
Si vous avez besoin d'un petit client (Python 2.x /3.x) qui peut télécharger de gros fichiers depuis FTP, vous pouvez le trouver ici . Il prend en charge le multithreading et les reconnexions (il surveille les connexions) et ajuste les paramètres de socket pour la tâche de téléchargement.
la source
chunk_size
est crucial. par défaut, c'est 1 (1 octet). cela signifie que pour 1 Mo, cela fera 1 million d'itérations. docs.python-requests.org/en/latest/api/…f.flush()
semble inutile. Qu'essayez-vous d'accomplir en l'utilisant? (votre utilisation de la mémoire ne sera pas de 1,5 Go si vous la laissez tomber).f.write(b'')
(siiter_content()
peut renvoyer une chaîne vide) doit être inoffensif etif chunk
peut donc également être supprimé.f.flush()
ne vide pas les données sur le disque physique. Il transfère les données vers l'OS. Habituellement, c'est suffisant, sauf en cas de panne de courant.f.flush()
rend le code plus lent ici sans raison. Le vidage se produit lorsque le tampon de fichier correspondant (à l'intérieur de l'application) est plein. Si vous avez besoin d'écritures plus fréquentes; passez le paramètre buf.size àopen()
.r.close()
C'est beaucoup plus facile si vous utilisez
Response.raw
etshutil.copyfileobj()
:Cela diffuse le fichier sur le disque sans utiliser de mémoire excessive et le code est simple.
la source
with
bloc (imbriqué) pour effectuer la requête:with requests.get(url, stream=True) as r:
with requests.get()
n'a été fusionnée que le 07/06/2017! Votre suggestion est raisonnable pour les personnes qui ont des demandes 2.18.0 ou ultérieures. Ref: github.com/requests/requests/issues/4136read
méthode:response.raw.read = functools.partial(response.raw.read, decode_content=True)
Pas exactement ce qu'OP demandait, mais ... c'est ridiculement facile de le faire avec
urllib
:Ou de cette façon, si vous souhaitez l'enregistrer dans un fichier temporaire:
J'ai regardé le processus:
Et j'ai vu le fichier augmenter, mais l'utilisation de la mémoire est restée à 17 Mo. Suis-je en train de manquer quelque chose?
la source
from urllib import urlretrieve
shutil.copyfileobj
avec le plus de votes, voir mes commentaires et ceux làVotre taille de bloc peut être trop grande, avez-vous essayé de supprimer cela - peut-être 1024 octets à la fois? (vous pouvez également utiliser
with
pour ranger la syntaxe)Soit dit en passant, comment déduisez-vous que la réponse a été chargée en mémoire?
Il semble que python n'est pas le rinçage des données dans un fichier, d'autres questions SO vous pouvez essayer
f.flush()
etos.fsync()
forcer la écriture de fichiers et de la mémoire libre;la source
f.flush(); os.fsync()
- être pourrait-il forcer l'écriture sur une mémoire libre.os.fsync(f.fileno())
def DownloadFile(url)