Запись потока чанка в файл асинхронно с использованием гипер
Я пытаюсь создать простую функцию, которая загружает удаленный файл в локальный путь к файлу с помощью гипер. Мне нужно, чтобы запись в файл также была асинхронной (в моем случае я использую tokio_fs
для этого). Вот код:
Посмотреть на детской площадке
// 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
будущее.
write_all
метод из Write
trait будет работать здесь, так как он принимает файл как изменяемую ссылку, но проблема в том, что он выполняет запись в том же потоке.
1 ответ
Вы не хотите использовать for_each
, io::write_all
потребляет цель и буфер в обмен на будущее, которое вернет цель и буфер, когда это будет сделано. Вы можете объединить это с Stream::fold
чтобы повторно использовать файл:
.fold(file, |file, chunk| {
io::write_all(file, chunk)
.map(|(f, _c)| f)
.map_err(|_| DownloadFileError::FileWrite)
})
.map(drop)
Смотрите также: