rust - 使用 hyper 将 block 流异步写入文件

标签 rust future borrow-checker rust-tokio hyper

我正在尝试创建一个简单的函数,使用 hyper 将远程文件下载到本地文件路径。我也需要异步写入文件(在我的例子中,我使用 tokio_fs)。这是代码:

View in the playground

// Parts of the code were omitted, see the playground for full source code
pub fn download_file(
    uri: Uri,
    file_location: &Path,
) -> Box<Future<Item = (), Error = DownloadFileError>> {
    let temp_dir_path = tempfile::tempdir().unwrap().into_path();
    let file_name = match file_location.file_name() {
        Some(file_name) => file_name,
        None => return Box::new(futures::failed(DownloadFileError::IncorrectFilePath)),
    };

    let temp_filepath = temp_dir_path.join(&file_name);

    let connector = HttpsConnector::new(2).unwrap();
    let client: Client<_, Body> = Client::builder().build(connector);

    let response_future = client
        .get(uri)
        .map_err(|err| DownloadFileError::GetRequest(err));

    let create_file_future =
        File::create(temp_filepath).map_err(|err| DownloadFileError::CreateFile(err));

    Box::new(
        response_future
            .join(create_file_future)
            .and_then(move |(res, file)| {
                res.into_body()
                    .map_err(|e| DownloadFileError::GetRequest(e))
                    .for_each(move |chunk| {
                        io::write_all(file, chunk)
                            .map(|_| ())
                            .map_err(|_| DownloadFileError::FileWrite)
                    })
            }),
    )
}

但是,我收到以下错误:

error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
  --> src/lib.rs:79:39
   |
75 |             .and_then(move |(res, file)| {
   |                                   ---- captured outer variable
...
79 |                         io::write_all(file, chunk)
   |                                       ^^^^ cannot move out of captured outer variable in an `FnMut` closure

从概念上讲,我理解错误的含义:由于 FnMut 通过可变引用捕获变量,因此我无法移动捕获的变量。但是,我不明白如何在给出的示例中解决这个问题,因为我需要将流写入 Join future 返回的文件。

Write trait 中的 write_all 方法可以在这里工作,因为它将文件作为可变引用,但问题是它在同一个线程上进行写入.

最佳答案

您不想使用 for_eachio::write_all消耗目标和缓冲区以换取 future ,该 future 将在完成时返回目标和缓冲区。您可以将其与 Stream::fold 结合使用重用文件:

.fold(file, |file, chunk| {
    io::write_all(file, chunk)
        .map(|(f, _c)| f)
        .map_err(|_| DownloadFileError::FileWrite)
})
.map(drop)

另见:

关于rust - 使用 hyper 将 block 流异步写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53330556/

相关文章:

java - 在 ThreadPoolExecutor 中实现优先级队列

javascript - ES6 Promises 和 PEP3148 Futures 的链式差异

rust - 手动删除引用包装器的Rust生命周期问题

rust - 仅用于借用检查的零宽度引用?

rust - 使用 Rust 创建周期性任务的最佳方法是什么?

rust - 应该如何处理 Rust 中的 Boxed trait 对象?

c++ - 是否存在序列化 boost::signals2 信号调用的现有方法?

rust - "Popping"来自 HashSet 的值

rust - 在存在借用的情况下,值(value)在闭包和组合器中过早下降

计算并生成重复结构字段的 Rust 宏