2015-03-12 9 views
6

Sto utilizzando rest-client per scaricare pagine di grandi dimensioni (circa 1,5 GB di dimensioni). Il valore recuperato viene memorizzato in memoria rispetto a quello salvato in un file. Come risultato il mio programma si blocca con failed to allocate memory (NoMemoryError).Utilizzo di rest-client per scaricare un file su disco senza caricare tutto in memoria prima

Tuttavia, non è necessario conservare questi dati in memoria, potrebbe persino essere salvato direttamente su disco.

Ho trovato "È possibile: (...) gestire manualmente la risposta (ad esempio per operare su di esso come un flusso piuttosto che leggerlo tutto in memoria) Vedere la documentazione di RestClient :: Request per ulteriori informazioni." su https://github.com/rest-client/rest-client Purtroppo dopo aver letto http://www.rubydoc.info/gems/rest-client/1.7.3/RestClient/Request non ho idea di come possa essere realizzato.

Sono anche consapevole del fatto che potrei utilizzare un'altra libreria (Using WWW:Mechanize to download a file to disk without loading it all in memory first) ma il mio programma sta già utilizzando rest-client.

codice semplificato:

data = RestClient::Request.execute(:method => :get, :url => url, :timeout => 3600) 
file = File.new(filename, 'w') 
file.write data 
file.close 

Codice - https://github.com/mkoniecz/CartoCSSHelper/blob/395deab626209bcdafd675c2d8e08d0e3dd0c7f9/downloader.rb#L126

+0

http://www.rubydoc.info/gems/rest-client/1.7.3/RestClient/Request#fetch_body-instance_method leggere le fonti di questo metodo e attuare smth come questo, ma a memorizzare i dati direttamente nel file. – iced

+0

È possibile utilizzare la libreria integrata OpenURI: 'require 'open-uri'; File.open (percorso, 'w') {| f | IO.copy_stream (open (url), f)} '. Se il file è di grandi dimensioni 'open' lo scriverà automaticamente su un Tempfile e ritornerà. Se il file è abbastanza piccolo, lo scriverà in un 'StringIO'. In entrambi i casi si avrà un oggetto io che è possibile copiare in blocco nella posizione desiderata. –

+0

Hai risolto questo problema con RestClient? Ho un problema simile ma non posso usare open-uri poiché non supporta le richieste POST. – Raoot

risposta

1

Un altro modo è utilizzare raw_response. Questo salva direttamente su un file, di solito in /tmp. Questo gestisce i reindirizzamenti senza problemi. Vedere Streaming Responses. Ecco il loro esempio:

>> raw = RestClient::Request.execute(
      method: :get, 
      url: 'http://releases.ubuntu.com/16.04.2/ubuntu-16.04.2-desktop-amd64.iso', 
      raw_response: true) 
=> <RestClient::RawResponse @code=200, @file=#<Tempfile:/tmp/rest-client.20170522-5346-1pptjm1>, @request=<RestClient::Request @method="get", @url="http://releases.ubuntu.com/16.04.2/ubuntu-16.04.2-desktop-amd64.iso">> 
>> raw.file.size 
=> 1554186240 
>> raw.file.path 
=> "/tmp/rest-client.20170522-5346-1pptjm1" 
2

La mia risposta originale promosso il superamento di un blocco per RestClient::Request#execute ma questo passato solo i dati al blocco, una volta piena risposta viene letto. Rendendo così l'esercizio inutile. Ecco come farlo correttamente:

File.open('/tmp/foo.iso', 'w') {|f| 
    block = proc { |response| 
     response.read_body do |chunk| 
     puts "Working on response" 
     f.write chunk 
     end 
    } 
    RestClient::Request.new(method: :get, url: 'http://mirror.pnl.gov/releases/xenial/ubuntu-16.04-server-amd64.iso', block_response: block).execute 
} 

È dal relativo rest-client project issue.

Nota: il reindirizzamento non funziona in questa modalità e si perde lo stato di uscita HTTP, i cookie, le intestazioni, ecc. Spero che questo problema venga risolto un giorno.

Problemi correlati