【问题标题】:How to unzip a Reqwest/Hyper response using streams?如何使用流解压缩 Reqwest/Hyper 响应?
【发布时间】:2018-05-22 15:19:07
【问题描述】:

我需要下载一个 60MB 的 ZIP 文件并解压缩其中的唯一文件。我想下载它并使用流提取它。如何使用 Rust 实现这一点?

fn main () {
    let mut res = reqwest::get("myfile.zip").unwrap();
    // extract the response body to myfile.txt
}

在 Node.js 中,我会这样做:

http.get('myfile.zip', response => {
  response.pipe(unzip.Parse())
  .on('entry', entry => {
    if (entry.path.endsWith('.txt')) {
      entry.pipe(fs.createWriteStream('myfile.txt'))
    }
  })
})

【问题讨论】:

  • 你看过箱子拉链了吗? github.com/mvdnes/zip-rs
  • 我做过,但我刚刚开始使用 rust,reqwest + zip 示例真的会派上用场。
  • 您是否考虑过接受这个问题的答案或开始悬赏?

标签: rust reqwest


【解决方案1】:

使用reqwest,您可以获得.zip 文件:

reqwest::get("myfile.zip")

由于reqwest 只能用于检索文件,因此zip 包中的ZipArchive 可用于解压文件。无法将.zip 文件流式传输到ZipArchive,因为ZipArchive::new(reader: R) 需要R 实现Read(由reqwestResponse 实现)和Seek,这不是由Response 实现。

作为一种解决方法,您可以使用临时文件:

copy_to(&mut tmpfile)

由于File 实现了SeekReadzip 可以在这里使用:

zip::ZipArchive::new(tmpfile)

这是所描述方法的一个工作示例:

extern crate reqwest;
extern crate tempfile;
extern crate zip;

use std::io::Read;

fn main() {
    let mut tmpfile = tempfile::tempfile().unwrap();
    reqwest::get("myfile.zip").unwrap().copy_to(&mut tmpfile);
    let mut zip = zip::ZipArchive::new(tmpfile).unwrap();
    println!("{:#?}", zip);
}

tempfile 是一个方便的 crate,它可以让你创建一个临时文件,所以你不必想一个名字。

【讨论】:

    【解决方案2】:

    这就是我从位于本地服务器上的存档 hello.zip 中读取内容为 hello world 的文件 hello.txt 的方式:

    extern crate reqwest;
    extern crate zip;
    
    use std::io::Read;
    
    fn main() {
        let mut res = reqwest::get("http://localhost:8000/hello.zip").unwrap();
    
        let mut buf: Vec<u8> = Vec::new();
        let _ = res.read_to_end(&mut buf);
    
        let reader = std::io::Cursor::new(buf);
        let mut zip = zip::ZipArchive::new(reader).unwrap();
    
        let mut file_zip = zip.by_name("hello.txt").unwrap();
        let mut file_buf: Vec<u8> = Vec::new();
        let _ = file_zip.read_to_end(&mut file_buf);
    
        let content = String::from_utf8(file_buf).unwrap();
    
        println!("{}", content);
    }
    

    这将输出hello world

    【讨论】:

    • 此示例是否将整个文件读入缓冲区?请记住,这是一个大文件。
    • 您可以使用read 和固定大小的缓冲区逐块读取。有关Read 的更多信息,请参阅此页面:doc.rust-lang.org/std/io/trait.Read.html