Каков наиболее эффективный способ чтения большого файла по частям без одновременной загрузки всего файла в память?

Каков наиболее эффективный универсальный способ чтения "больших" файлов (которые могут быть текстовыми или двоичными) без перехода на unsafe территорию? Я был удивлен, как мало релевантных результатов было, когда я выполнял веб-поиск по запросу "Руст читал большой файл кусками".

Например, один из моих вариантов использования является вычисление контрольной суммы MD5 для файла с помощью rust-crypto (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(())
}

Ответ 1

Я не думаю, что вы можете написать код более эффективный, чем этот. fill_buf в BufReader над File - это просто прямой вызов read(2).

Тем не менее, BufReader не является действительно полезной абстракцией, когда вы используете его таким образом; вероятно, было бы менее неудобно просто вызывать file.read(&mut buf) напрямую.