2017-01-03 11 views
3

ハイパーで大容量のファイル(500MB)をダウンロードし、ダウンロードに失敗した場合は再開することができます。ハイパーで大きなファイルをダウンロードしてエラーで再開するにはどうすればよいですか?

受信したデータの各チャンクに対していくつかの機能を実行する方法はありますか。 send()メソッドはResult<Response>を返しますが、チャンクでイテレータを返すメソッドはResponseにありません。理想的には私のような何かを行うことができるだろう:

client.get(&url.to_string()) 
    .send() 
    .map(|mut res| { 
     let mut chunk = String::new(); 
     // write this chunk to disk 
    }); 

を、このことが可能であり、またはハイパーは、ファイル全体をダウンロードした後mapのみ呼び出されますか?

+0

'read'自体がチャンクされていますか?一度にNバイトを読み取ることができます。私はそれがダウンロードされたNバイトに正確に相関するかどうか、またはちょうどバッファされた読み取りであるかどうかはわかりません。しかし、データを適切に保存する限り、それは重要ではありません。 – Kroltan

答えて

3

受信したデータの各チャンクに対していくつかの機能を実行する方法はありますか。

ハイパーのResponseは、Readを実装しています。これは、Responseがストリームであることを意味し、通常はストリームと同様に、任意のチャンクを読み込むことができます。

ここでは、ICECatから大きなファイルをダウンロードするためのコードを紹介します。私はReadインターフェイスを使用して、端末のダウンロードの進行状況を表示しています。

ここで変数responseはHyperのResponseのインスタンスです。

{ 
    let mut file = try_s!(fs::File::create(&tmp_path)); 
    let mut deflate = try_s!(GzDecoder::new(response)); 

    let mut buf = [0; 128 * 1024]; 
    let mut written = 0; 
    loop { 
     status_line! ("icecat_fetch] " (url) ": " (written/1024/1024) " MiB."); 
     let len = match deflate.read(&mut buf) { 
      Ok(0) => break, // EOF. 
      Ok(len) => len, 
      Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue, 
      Err(err) => return ERR!("{}: Download failed: {}", url, err), 
     }; 
     try_s!(file.write_all(&buf[..len])); 
     written += len; 
    } 
} 

try_s!(fs::rename(tmp_path, target_path)); 
status_line_clear(); 

私はハイパーで大きなファイル(500メガバイト)をダウンロードし、ダウンロードが失敗した場合に再開できるようにしたいです。

これは、通常、HTTP "Range"ヘッダー(RFC 7233参照)で実装されます。

「範囲」ヘッダーがサポートされているサーバーはありません。私はカスタムHTTPスタックを備え、適切な "Range"サポートがない、または何らかの理由で "Range"ヘッダーが無効になっているサーバーをたくさん見てきました。したがって、HyperのResponseチャンクをスキップすることは必要な代替手段かもしれません。

しかし、時間とトラフィックを節約したい場合は、停止したダウンロードを再開するための主な手段は、「範囲」ヘッダーを使用することです。

関連する問題