2017-01-03 75 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

有沒有什麼方法可以爲每個接收的數據塊運行一些函數?

Hyper's Response implements 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(); 

我想與超下載大文件(500MB),並能夠恢復,如果下載失敗。

這通常使用HTTP「範圍」標頭實現(參見RFC 7233)。

並非每個服務器都支持「範圍」標題。我見過很多帶有自定義HTTP堆棧的服務器,但沒有適當的「範圍」支持,或者出於某種原因禁用了「範圍」標頭。所以跳過Hyper的Response塊可能是必要的回退。

但是,如果您想節省時間和流量,那麼恢復停止下載的主要方法應該是使用「範圍」標題。