Rust使用read_exact读文件报Failed to fill whole buffer错误排查
问题根因
你之前排查的两个方向(缓冲区零初始化、文件实际大小和缓冲区长度一致)都是正确的,错误和这两点无关。
触发报错的核心原因是:调用write_all写入文件后,File实例内置的读写游标会停在本次写入内容的末尾位置,此时直接调用read_exact会从游标当前位置(也就是文件结尾处)开始尝试读取数据,自然无法填满和文件等长的缓冲区,最终抛出failed to fill whole buffer错误。
修复方案
读取文件前,将读写游标重置到文件起始位置即可,不需要重新打开文件。如果场景不需要保留写权限,也可以写完关闭句柄后重新以只读模式打开文件读取。
最简便的修复方式是在调用read_exact前加一行游标重置代码:
// 将读写游标移动到文件偏移量为0的起始位置 file.seek(std::io::SeekFrom::Start(0)).unwrap();
修正后可运行的完整代码
use std::fs::{File, OpenOptions}; use std::io::prelude::*; use std::io::SeekFrom; use bincode::*; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct Node { pub name: String, end_ptr: u32 // 下一个节点的字节偏移量 } impl Node { pub fn to_string(&self) -> String { return self.name.clone(); } } fn main() { let node = Node { name: String::from("node_1"), end_ptr: 0 }; let node_as_buf = bincode::serialize(&node).unwrap(); let len_of_bytes_serialised: usize = node_as_buf.len(); let mut file = OpenOptions::new() .read(true) .write(true) .create(true) .truncate(true) .open("test.txt") .unwrap(); match file.write_all(&node_as_buf) { Ok(_) => println!("Write success"), Err(err) => println!("{}", &err) } println!("文件大小:{}", file.metadata().unwrap().len()); println!("序列化字节长度:{}", len_of_bytes_serialised); // 核心修复:重置游标到文件开头 file.seek(SeekFrom::Start(0)).unwrap(); let mut buffer = vec![0; len_of_bytes_serialised]; match file.read_exact(&mut buffer[..]) { Ok(_) => println!("Read success"), Err(err) => println!("{}", &err) } let read_node: Node = bincode::deserialize(&buffer[..]).unwrap(); // 校验读取结果正确性 assert_eq!(node, read_node); }
额外说明
- Rust标准库的
File读写是基于游标位置的顺序操作,写入、读取动作都会向后移动游标,涉及写完立刻读的场景必须手动调整游标位置 - 生产环境不建议直接使用
unwrap()处理IO、序列化结果,建议对错误做显式匹配,避免意外panic
内容的提问来源于stack exchange,提问作者m.tracey
相关产品推荐
相关产品推荐

