IO 操作
问题
Rust 的 IO 模型是怎样的?Read/Write trait 如何使用?
答案
Rust 的 IO 基于 std::io 模块中的两个核心 trait:Read 和 Write。
Read 与 Write
use std::io::{self, Read, Write, BufRead, BufReader, BufWriter};
use std::fs::File;
fn main() -> io::Result<()> {
// === 读取文件 ===
// 方式 1:一次性读取全部内容
let content = std::fs::read_to_string("input.txt")?;
// 方式 2:缓冲读取(推荐大文件)
let file = File::open("input.txt")?;
let reader = BufReader::new(file);
for line in reader.lines() {
println!("{}", line?);
}
// === 写入文件 ===
// 方式 1:一次性写入
std::fs::write("output.txt", "hello")?;
// 方式 2:缓冲写入(推荐大量写入)
let file = File::create("output.txt")?;
let mut writer = BufWriter::new(file);
writer.write_all(b"hello world")?;
// BufWriter 在 drop 时自动 flush
Ok(())
}
核心 trait 关系
| Trait | 作用 | 关键方法 |
|---|---|---|
Read | 字节读取 | read(), read_to_string(), read_exact() |
Write | 字节写入 | write(), write_all(), flush() |
BufRead | 缓冲读取 | read_line(), lines(), fill_buf() |
Seek | 随机访问 | seek(), stream_position() |
泛型 IO:面向 trait 编程
use std::io::{Read, Write};
/// 接受任何实现了 Read 的类型
fn count_bytes(mut reader: impl Read) -> io::Result<usize> {
let mut buf = Vec::new();
reader.read_to_end(&mut buf)?;
Ok(buf.len())
}
// 可以传文件、网络流、内存 Cursor 等
let bytes = count_bytes(File::open("test.txt")?)?;
let bytes = count_bytes(std::io::Cursor::new(b"hello"))?;
let bytes = count_bytes(&b"raw bytes"[..])?;
实践建议
- 小文件用
fs::read_to_string/fs::write - 大文件用
BufReader/BufWriter - 函数参数用
impl Read/impl Write提高通用性
常见面试问题
Q1: 为什么需要 BufReader/BufWriter?
答案:
直接使用 Read/Write 每次操作都是系统调用(syscall),开销大。BufReader/BufWriter 在内存中维护缓冲区,减少系统调用次数,显著提升性能。默认缓冲区 8KB。
Q2: Cursor 有什么用?
答案:
std::io::Cursor<T> 为内存中的字节切片提供 Read/Write/Seek 实现,常用于测试(不需要真实文件)和内存中的 IO 操作。