Rust中如何结合BufReader使用bincode::deserialize_from加速大文件读取
问题场景
- 以下为演示用示例代码,实际业务场景需要处理以相同写入方式生成的超大型二进制文件
- 待读取的超大二进制文件均为自行通过bincode序列化写入
- 核心目标:通过Bincode生成大体积序列化文件,后续可迭代遍历文件内存储的结构化数据
原有演示代码如下:
#[macro_use] extern crate serde; extern crate bincode; // use std::fs::File; use bincode::serialize_into; use std::io::BufWriter; #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct MyStruct { counter: Vec<u32>, offset: usize, } impl MyStruct { // 省略其他逻辑 pub fn new(counter: Vec<u32>, offset: usize) -> Self { Self { counter, offset } } } fn main() { let mut vec = Vec::new(); vec.push(100); vec.push(500); vec.push(100); vec.push(500); vec.push(100); vec.push(500); let m = MyStruct::new(vec, 0); // 填充counter向量内容 let mut f = BufWriter::new(File::create("foo2.bar").unwrap()); serialize_into(&mut f, &m).unwrap(); let mut vec = Vec::new(); vec.push(100); vec.push(600); vec.push(100); vec.push(500); vec.push(100); vec.push(600); vec.push(500); vec.push(101241241); vec.push(600); let m2 = MyStruct::new(vec, 35); serialize_into(&mut f, &m2).unwrap(); drop(f); let input = File::open("foo2.bar").unwrap(); // let buffered = BufReader::new(input); let mut vecs: Vec<MyStruct> = Vec::new(); loop { match bincode::deserialize_from(&input) { Ok(file) => vecs.push(file), Err(error) => break, }; } }
当前实现直接对原始File句柄执行读取,IO效率极低导致运行速度很慢。已经编写了包裹File实例的BufReader初始化代码,需要修改逻辑让bincode::deserialize_from使用BufReader提升读取性能,已完成的初始化代码如下:
let input = File::open("foo2.bar").unwrap(); let buffered = BufReader::new(input);
修改方法
bincode::deserialize_from的参数只要求实现std::io::Read trait,BufReader本身就实现了该trait,只需要注意两个细节即可直接使用:
BufReader实例必须声明为可变(mut),因为反序列化读取过程会修改其内部缓冲区和读取游标- 传入
deserialize_from时传BufReader的可变引用,不要按值传入,否则第一次反序列化会拿走BufReader的所有权,后续循环无法继续读取剩余内容
完整修改步骤
- 提前引入
BufReader:use std::io::BufReader; - 将原有读取逻辑替换为以下代码:
let input = File::open("foo2.bar").unwrap(); let mut buffered = BufReader::new(input); let mut vecs: Vec<MyStruct> = Vec::new(); loop { match bincode::deserialize_from(&mut buffered) { Ok(file) => vecs.push(file), Err(e) => { // 生产环境建议区分错误类型:仅遇到文件末尾错误时正常退出,其他错误抛出处理 break } }; }
注意事项
- 示例中遇到错误直接break的写法仅适用于演示,实际业务场景需要判断错误类型:如果是IO错误且错误kind为
UnexpectedEof才代表文件正常读取完毕,其余错误(比如序列化格式损坏、IO异常)需要单独处理,避免静默失败。 - 对于GB级以上的超大文件,还可以根据磁盘页大小调整
BufReader的缓冲区容量(通过BufReader::with_capacity初始化),进一步减少系统调用次数提升性能。
内容的提问来源于stack exchange,提问作者tradinggy
相关产品推荐
相关产品推荐

