我的需求是一个大文件上传,使用curl -T <file>
,服务器端是一个HTTP Server在Rust中,实现可以是actix-web
(或者hyper
,如果其他实现更合适的话),使用HTTP/1.1
,在HTTP/1.1
中,服务器只能读取文件上传数据流一次,我想计算文件的MD5
,SHA-1
和SHA-256
(或BLAKE3
),而不需要将文件数据流读入内存,然后上传到S3,如果有并行计算的解决方案会更好,但可能会更复杂,关键还是要重用流。
最好不要使用channel
来实现它,因为流将流经多个channel
来计算校验和,这可能比重用流来同时计算性能更低。
这需要基于Rust 2021 Edition,actix-web
4.x版本(最新是4.3.0),而且如果使用tokio
,至少要1.0.0+(我目前是1.25.0),这是因为Rust中库版本的兼容性太差,各个次要版本之间可能存在API不兼容的问题。
请问我的需求是否可以用Rust来实现?在Go语言中,除了io.Pipe
,似乎没有更好的解决方案,但是io.Pipe
的性能看起来并不好。
非常感谢您的建议和耐心!
更新:您可以使用Go或Java来满足此需求。
2条答案
按热度按时间vof42yt11#
不把文件放到内存中就不可能进行计算,至少在标准硬件上是这样的,解决方案是用
BufRead
的实现程序(比如BufReader
)来分块阅读文件。这在synchronous rust中是完全可能的,但是因为你指定时雄,所以我使用tokio的IO类型和traits创建了这个async,你可以使用标准库的IO类型和traits创建同样的东西,它们的命名是相似的。
首先,一个函数接受一个读取器,更新一个哈希函数切片,然后将这些字节写入一个写入器,这基本上是
tokio::io::copy_buf
,但中间有哈希函数。这使用了digest机箱中的一个特征:幸运的是,已经有了使用digest的特定哈希函数的实现:md-5、sha1和sha2(确保您使用的版本依赖于相同的digest版本,目前这些版本都是0.10.5)。
下面是正在使用的函数:
如果你想更进一步,你可以创建一个 Package 器类型,为所有的
Update
类型实现AsyncWrite
,这样你就不需要分离hashers
和writer
了,你也可以反过来把hashers
分离成你特定的散列函数类型或者特定数量的泛型参数。这避免了dyn
。我在这里使用了dyn
切片,这样在不太具体的情况下对其他人有帮助。Here's a link to the whole thing on playground.由于缺少依赖项,它无法编译。
a6b3iqyw2#
下面是Go语言的一个实现思路:计算请求主体的校验和,同时将其写入S3存储器。
但是现在我在想,是否可以先通过
io.MultiWriter
计算Checksum,然后再决定是否上传Request Body,但是在这一点上,似乎没有好的方法可以将已经读取的Request Body用作上传逻辑,而不将其读取到内存中或写入临时文件中。