Rust入门失败之Read&Write

Rust std::io的核心是ReadWrite两个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调用请求.

    Screen Shot 2019-11-28 at 00.55.56

  • stdin读取. 在C中, 如果多个线程同时从stdin中读数据会造成未定义的行为. 标准的做法是加锁. Rust也是一样, 唯一的区别是加锁这个动作是Rust API自带提供的.

    1
    2
    3
    4
    5
    6
    use 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
    7
    use 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中. 如果这时候写入有错误的话会被忽略.