【问题标题】:What is the most efficient way to read a large file in chunks without loading the entire file in memory at once?在不一次将整个文件加载到内存中的情况下,分块读取大文件的最有效方法是什么?
【发布时间】:2019-04-08 02:38:33
【问题描述】:

什么是读取“大”文件(可能是文本或二进制文件)而不进入unsafe 领域的最有效的通用方法?当我在网络上搜索“rust read large file in chunks”时,我很惊讶有这么少的相关结果。

例如,我的一个用例是使用 rust-crypto 计算文件的 MD5 校验和(Md5 模块允许您迭代地添加 &[u8] 块)。

这是我所拥有的,它的性能似乎比其他一些方法(如read_to_end)略好:

use std::{
    fs::File,
    io::{self, BufRead, BufReader},
};

fn main() -> io::Result<()> {
    const CAP: usize = 1024 * 128;
    let file = File::open("my.file")?;
    let mut reader = BufReader::with_capacity(CAP, file);

    loop {
        let length = {
            let buffer = reader.fill_buf()?;
            // do stuff with buffer here
            buffer.len()
        };
        if length == 0 {
            break;
        }
        reader.consume(length);
    }

    Ok(())
}

【问题讨论】:

  • 为什么要关闭 fill_buf?我有这个关闭修复的问题。能否请您指出正确的方向。
  • @Townsheriff,你的意思是,为什么reader.fill_buf()? 在一个块中(let length = { ... })?如果是这样,那是因为 2016 年的借用检查器不像现在那么复杂。如果我将fill_bufconsume 放在同一个范围内,rustc 会抱怨cannot borrow `reader` as mutable more than once at a timefill_buf 返回对底层读者的引用,因此将其置于较短的生命周期中可能会解决您的问题。
  • 是的,这正是我在今天稳定的 rust 版本中遇到的。非常感谢和欢呼!

标签: file io rust


【解决方案1】:

我认为没有比这更高效的代码了。 fill_buf 上的 BufReader 上的 Filebasically just a straight call to read(2)

也就是说,BufReader 在您这样使用时并不是一个真正有用的抽象;直接拨打file.read(&amp;mut buf) 可能不会那么尴尬。

【讨论】:

  • 感谢您的回答!我认为BufReader 对我很有用,因为当我读到阅读器末尾时它为我调整了缓冲区的大小,但我才意识到这很简单......
  • 因为它调整了缓冲区的大小——我怀疑它调整了缓冲区的大小,但是切片可能被缩短以反映读取的字节数。但是你是对的,Read::read 的返回值告诉你有多少缓冲区是有效的。使用它非常重要,否则您可能会遇到像 Heartbleed 这样的问题,即缓冲区与旧内容重用!这可能是使用BufReader 的好理由。
  • 对不起,你说得对,我的意思是“缩短了缓冲区的长度”。
猜你喜欢
  • 1970-01-01
  • 2014-02-01
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2014-09-15
相关资源
最近更新 更多