Rust 如何实时从hyper::Response解压XZ数据?

Rust 如何实时从hyper::Response解压XZ数据?,rust,hyper,xz,Rust,Hyper,Xz,我正在用下载一个XZ文件,我希望通过从每个传入的文件中提取尽可能多的内容并立即将结果写入磁盘,而不是先下载整个文件,然后解压缩,从而以解压缩形式将其保存到磁盘 有一个实现XZ格式的板条箱。然而,它似乎不支持一个模型,在这个模型中,调用者重复地提供部分输入并获得部分输出 相反,XzDecoder通过一个参数接收输入字节,我不知道如何将这两个东西粘合在一起。是否有办法将数据馈送到XzDecoder 到目前为止,我发现的唯一线索是这个,其中包含对私有类型的引用,理论上我可以在代码中复制它——但也许有更

我正在用下载一个XZ文件,我希望通过从每个传入的文件中提取尽可能多的内容并立即将结果写入磁盘,而不是先下载整个文件,然后解压缩,从而以解压缩形式将其保存到磁盘

有一个实现XZ格式的板条箱。然而,它似乎不支持一个模型,在这个模型中,调用者重复地提供部分输入并获得部分输出

相反,
XzDecoder
通过一个参数接收输入字节,我不知道如何将这两个东西粘合在一起。是否有办法将数据馈送到
XzDecoder

到目前为止,我发现的唯一线索是这个,其中包含对私有类型的引用,理论上我可以在代码中复制它——但也许有更简单的方法

XzDecoder
似乎不支持类似Python的decompressobj模型,在该模型中,调用者重复提供部分输入并获得部分输出

有一种方法可以完全满足你的需要。非常粗糙的未经测试的代码,需要正确的错误处理等,但我希望您能理解:

fn进程(body:hyper::body::body){
让mut decoder=xz2::stream::stream::new_stream_decoder(1000,0).unwrap();
主体。对于每一个(|块|{
让mut buf:Vec=Vec::new();
if-let-Ok(u)=decoder.process_-vec(&chunk,&mut-buf,Action::Run){
//将buf写入磁盘
}
好(())
}).wait().unwrap();
}
基于此,我提出了以下工作代码:

extern crate failure;
extern crate hyper;
extern crate tokio;
extern crate xz2;

use std::fs::File;
use std::io::Write;
use std::u64;

use failure::Error;
use futures::future::done;
use futures::stream::Stream;
use hyper::{Body, Chunk, Response};
use hyper::rt::Future;
use hyper_tls::HttpsConnector;
use tokio::runtime::Runtime;

fn decode_chunk(file: &mut File, xz: &mut xz2::stream::Stream, chunk: &Chunk)
                -> Result<(), Error> {
    let end = xz.total_in() as usize + chunk.len();
    let mut buf = Vec::with_capacity(8192);
    while (xz.total_in() as usize) < end {
        buf.clear();
        xz.process_vec(
            &chunk[chunk.len() - (end - xz.total_in() as usize)..],
            &mut buf,
            xz2::stream::Action::Run)?;
        file.write_all(&buf)?;
    }
    Ok(())
}

fn decode_response(mut file: File, response: Response<Body>)
                   -> impl Future<Item=(), Error=Error> {
    done(xz2::stream::Stream::new_stream_decoder(u64::MAX, 0)
        .map_err(Error::from))
        .and_then(|mut xz| response
            .into_body()
            .map_err(Error::from)
            .for_each(move |chunk| done(
                decode_chunk(&mut file, &mut xz, &chunk))))
}

fn main() -> Result<(), Error> {
    let client = hyper::Client::builder().build::<_, hyper::Body>(
        HttpsConnector::new(1)?);
    let file = File::create("hello-2.7.tar")?;
    let mut runtime = Runtime::new()?;
    runtime.block_on(client
        .get("https://ftp.gnu.org/gnu/hello/hello-2.7.tar.xz".parse()?)
        .map_err(Error::from)
        .and_then(|response| decode_response(file, response)))?;
    runtime.shutdown_now();
    Ok(())
}
外部板条箱故障;
外部板条箱;
外部板条箱东京;
外部板条箱xz2;
使用std::fs::File;
使用std::io::Write;
使用std::u64;
使用失败::错误;
使用futures::future::done;
使用futures::stream::stream;
使用hyper::{Body,Chunk,Response};
使用hyper::rt::Future;
使用hyper_tls::HttpsConnector;
使用tokio::runtime::runtime;
fn解码_块(文件:&mut文件,xz:&mut xz2::流::流,块:&chunk)
->结果{
设end=xz.total_in()为usize+chunk.len();
设mut buf=Vec::具有_容量(8192);
而(xz.total_in()作为usize)暗示未来{
完成(xz2::stream::stream::new_stream_解码器(u64::MAX,0)
.map_err(错误::from))
.然后(| mut xz |响应
.进入_body()
.map_err(错误::from)
.对于每个(移动|块|完成(
解码_chunk(&mut文件,&mut xz,&chunk)))
}
fn main()->结果{
让client=hyper::client::builder()。生成::(
HttpsConnector::新(1);
让file=file::create(“hello-2.7.tar”)?;
让mut runtime=runtime::new()?;
runtime.block_on(客户端
.get(“https://ftp.gnu.org/gnu/hello/hello-2.7.tar.xz“.parse()?)
.map_err(错误::from)
然后(|响应|解码响应(文件,响应))?;
runtime.shutdown_now();
好(())
}

谢谢,这很有效!是我最后得到的。@mephi42请将代码作为单独的答案发布。评论是非常短暂的。