如何在 Rust 中创建可用作 Reader、Writer 或 Seek 的内存对象?

How to create an in-memory object that can be used as a Reader, Writer, or Seek in Rust?

我需要一个完全在内存中的对象,我可以将其提供给 BufReaderBufWriter。类似于 Python 的 StringIO。我想使用通常与 Files.

一起使用的方法写入和读取这样的对象

有没有办法使用标准库来做到这一点?

其实是有办法的:Cursor<T>!
另请阅读 ,了解为什么它更容易

在文档中可以看到有如下实现:

impl<T> Seek for Cursor<T> where T: AsRef<[u8]>
impl<T> Read for Cursor<T> where T: AsRef<[u8]>
impl Write for Cursor<Vec<u8>>
impl<T> AsRef<[T]> for Vec<T>

从这里你可以看出你可以像普通文件一样使用类型Cursor<Vec<u8>>,因为ReadWriteSeek 已针对该类型实施!

小例子(Playground):

use std::io::{Cursor, Read, Seek, SeekFrom, Write};

// Create fake "file"
let mut c = Cursor::new(Vec::new());

// Write into the "file" and seek to the beginning
c.write_all(&[1, 2, 3, 4, 5]).unwrap();
c.seek(SeekFrom::Start(0)).unwrap();

// Read the "file's" contents into a vector
let mut out = Vec::new();
c.read_to_end(&mut out).unwrap();

println!("{:?}", out);

有关更有用的示例,请查看上面链接的文档。

如果要将BufReader与in-memoryString一起使用,可以使用as_bytes()方法:

use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;

fn read_buff<R: Read>(mut buffer: BufReader<R>) {
    let mut data = String::new();
    let _ = buffer.read_line(&mut data);

    println!("read_buff got {}", data);
}

fn main() {
    read_buff(BufReader::new("Potato!".as_bytes()));
}

这会打印 read_buff got Potato!。这种情况不需要使用游标。

要将 in-memory StringBufWriter 一起使用,您可以使用 as_mut_vec 方法。不幸的是,它是 unsafe,我还没有找到任何其他方法。我不喜欢 Cursor 方法,因为它会消耗向量,而且我还没有找到将 CursorBufWriter 一起使用的方法。

use std::io::BufWriter;
use std::io::Write;

pub fn write_something<W: Write>(mut buf: BufWriter<W>) {
    buf.write("potato".as_bytes());
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::{BufWriter};

    #[test]
    fn testing_bufwriter_and_string() {
        let mut s = String::new();

        write_something(unsafe { BufWriter::new(s.as_mut_vec()) });

        assert_eq!("potato", &s);
    }
}

你不需要 Cursor 大多数时候

object that I can give to BufReader and BufWriter

BufReader 需要一个实现 Read:

的值
impl<R: Read> BufReader<R> {
    pub fn new(inner: R) -> BufReader<R>
}

BufWriter 需要一个实现 Write:

的值
impl<W: Write> BufWriter<W> {
    pub fn new(inner: W) -> BufWriter<W> {}
}

如果您查看 Read 的实现者,您会发现 impl<'a> Read for &'a [u8]

如果您查看 Write 的实现者,您会发现 impl Write for Vec<u8>

use std::io::{Read, Write};

fn main() {
    // Create fake "file"
    let mut file = Vec::new();

    // Write into the "file"
    file.write_all(&[1, 2, 3, 4, 5]).unwrap();

    // Read the "file's" contents into a new vector
    let mut out = Vec::new();
    let mut c = file.as_slice();
    c.read_to_end(&mut out).unwrap();

    println!("{:?}", out);
}

写入 Vec 将始终附加到末尾。我们还对可以更新的 Vec 进行了切片。每次读取 c 都会使切片越来越远,直到它为空。

Cursor的主要区别:

  • 无法查找数据,因此无法轻松重新读取数据
  • 除结尾外无法写入任何地方