是否可以从文件创建流而不是将文件内容加载到内存中?

2024-04-12

我目前正在使用rusoto_s3lib 将文件上传到 S3。我发现的所有示例都执行相同的操作:打开文件,将文件的完整内容读入内存(Vec<u8>),然后将 Vec 转换为ByteStream(它实现了From<Vec<u8>>)。这是一个代码示例:

fn upload_file(&self, file_path: &Path) -> FileResult<PutObjectOutput> {
    let mut file = File::open(file_path)?;
    let mut file_data: Vec<u8> = vec![];
    file.read_to_end(&mut file_data)?;

    let client = S3Client::new(Region::UsEast1);
    let mut request = PutObjectRequest::default();
    request.body = Some(file_data.into());

    Ok(client.put_object(request).sync()?)
}

这对于小文件来说可能是可以接受的,但是(我假设)一旦您尝试上传大小大于可用堆内存的文件,这种技术就会崩溃。

另一种创建方法ByteStream is by 使用这个初始化器 https://rusoto.github.io/rusoto/rusoto_core/struct.ByteStream.html#method.new它接受一个实现的对象Stream特征。我假设File会实现这个特性,但事实似乎并非如此。

我的问题:

是否有某种类型可以由File它实现了Stream?是制作我自己的元组结构的正确解决方案吗File并实施Stream本身,这个实现是微不足道的吗?是否有其他我没有看到的解决方案,或者我只是误解了上面代码中的内存分配方式?


是否有某种类型可以从实现 Stream 的 File 构造?

不,不幸的是。没有内置任何东西std, futures or tokio目前可以直接执行此操作。

由于 Stream 项目的“分离”性质,这样的实现必须为每个传入数据片分配一个新的拥有的缓冲区并将其移交给调用者。那效率不会很高。直到 Rust 语言拥有泛型关联类型 (GAT)(希望在明年),我们才能满意地解决这个问题。查看this futures-rs ticket https://github.com/rust-lang/futures-rs/issues/2006 and Niko 的异步采访 #2 https://smallcultfollowing.com/babysteps/blog/2019/12/10/async-interview-2-cramertj-part-2/了解更多详情。

话虽这么说,现在有一些用例Stream底层 IO 之上的门面是理想的并且足够好。

制作我自己的元组结构(包装 File 并实现 Stream 本身)的正确解决方案是正确的解决方案吗?这个实现很简单吗?

For futures-0.1认为rusoto取决于,有几种方法可以实现这一点:

  • 实施Stream包装 a 的结构体的特征Read
  • 利用futures效用函数,例如futures::stream::poll_fn
  • tokio-codec-0.1具有优秀的FramedRead已经实施的Stream

第三个肯定是最简单的:

use futures::stream::Stream;  // futures = "0.1.29"
use rusoto_core::{ByteStream, Region};  // rusoto_core = "0.42.0"
use rusoto_s3::{PutObjectOutput, PutObjectRequest, S3Client, S3};  // rusoto_s3 = "0.42.0"
use std::{error::Error, fs::File, path::Path};
use tokio_codec::{BytesCodec, FramedRead};  // tokio-codec = "0.1.1"
use tokio_io::io::AllowStdIo;  // tokio-io = "0.1.12"

fn upload_file(file_path: &Path) -> Result<PutObjectOutput, Box<dyn Error>> {
    let file = File::open(file_path)?;
    let aio = AllowStdIo::new(file);
    let stream = FramedRead::new(aio, BytesCodec::new()).map(|bs| bs.freeze());

    let client = S3Client::new(Region::UsEast1);
    let mut request = PutObjectRequest::default();
    request.body = Some(ByteStream::new(stream));

    Ok(client.put_object(request).sync()?)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以从文件创建流而不是将文件内容加载到内存中? 的相关文章

随机推荐