【问题标题】:How to create an in-memory object that can be used as a Reader, Writer, or Seek in Rust?如何在 Rust 中创建可用作 Reader、Writer 或 Seek 的内存对象?
【发布时间】:2017-04-25 11:45:19
【问题描述】:

我需要一个完全在内存中的对象,我可以将它提供给BufReaderBufWriter。类似于 Python 的StringIO。我想使用通常与Files 一起使用的方法来写入和读取这样的对象。

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

【问题讨论】:

    标签: rust in-memory


    【解决方案1】:

    其实有办法:Cursor<T>!
    也请阅读 Shepmaster's answer 了解为什么它更容易

    在文档中你可以看到有以下impls:

    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&lt;Vec&lt;u8&gt;&gt; 类型,因为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);
    

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

    【讨论】:

      【解决方案2】:

      如果您想将BufReader 与内存中的String 一起使用,您可以使用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!。这种情况下不需要使用游标。

      要将内存中的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后,您可以get the Vec back
      • @Shepmaster 太棒了!然后我可以使用from_utf8 转换为字符串,from_utf8 似乎避免了向量的复制,所以它应该是有效的,也可以使用 `from_utf8_unchecked' 这应该是一个简单的举动。
      【解决方案3】:

      你不需要Cursor大部分时间

      我可以给BufReaderBufWriter的对象

      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&lt;'a&gt; Read for &amp;'a [u8]

      如果你查看Write的实现者,你会发现impl Write for Vec&lt;u8&gt;

      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的主要区别:

      • 无法查找数据,无法轻松重新读取数据
      • 只能写到结尾

      【讨论】:

      • 这很棒。这是我们一年多前无法做到的事情吗?
      • @liszt 不,这些实现存在于 Rust 1.0 中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 2014-01-16
      • 1970-01-01
      • 2017-06-10
      • 2017-03-02
      相关资源
      最近更新 更多