Rust std::io
的核心是Read
和Write
两个trait.
Readers
std::io::Read
的所有方法都是&mut self
, 也就是必须拥有对象的mut reference.read
方法, 函数原型:1
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
- 从对象里读取最长不超过
buf.len()
长度的字节数据. - 如果返回0, 有两种可能:
- 一是可能到达了EOF(End Of File), 这个对象不会再有任何数据可读;
- 二是buf长度为0.
- 这个函数不能依赖buf中任何原有的数据, 但也不保证函数调用后buf的内容会是什么. 实现时建议正常点, 写入buf就好.
- buf需要提前初始化, 否则undefined behavior.
- 从对象里读取最长不超过
还有其它的一些read函数:
read_to_end
: 一直读到EOF为止, 最好不要调用不信任的Reader的这个方法, 比如网络数据.read_to_string
: 读到&mut string
参数中, 前提条件要是有效的UTF-8字符, 否则会报错.read_exact
: 读指定长度, 如果数据提前结尾, 那么会报错.
BufRead
是带缓冲区的Reader, 类似fread(fread一次会预读一个blocksize大小的数据块). BufRead也是类似, 它提供了一个read_line函数, 读取一行, 而实际内部调用了read, 可能预读了8k的大小, 足够满足后面几百次的read_line调用请求.从
stdin
读取. 在C中, 如果多个线程同时从stdin中读数据会造成未定义的行为. 标准的做法是加锁. Rust也是一样, 唯一的区别是加锁这个动作是Rust API自带提供的.1
2
3
4
5
6use std::io;
let stdin = io::stdin();
for line in stdin.lock().lines() {
println!("{}", line);
}从文件读取.
File::open
默认返回的File
对象只实现了Read
trait, 不带BufRead
trait. 因此需要手动创建一个BufReader
struct.1
2
3
4
5
6
7use std::io::BufReader;
use std::fs::File;
let f = File::open("log.txt")?;
let reader = BufReader::new(f);
// Or with_capacity
// let reader = BufReader::with_capacity(10, f);
Writers
- 和Read类似, 实现
Write
trait, 有三个主要的方法:write
,write_all
,flush
. - 同样也有
BufWriter
, 如果BufWriter
对象被drop, 那么缓冲区内所有的数据会被写入底层的writer中. 如果这时候写入有错误的话会被忽略.