rust in-memory

¿Cómo crear un objeto en memoria que se pueda usar como Lector, Escritor o Buscar en Rust?



in-memory (3)

Necesito un objeto completamente en memoria que puedo dar a BufReader y BufWriter . Algo como el StringIO de Python. Quiero escribir y leer desde un objeto de este tipo utilizando métodos que normalmente se usan con File s.

¿Hay alguna manera de hacer esto usando la biblioteca estándar?


De hecho hay un camino. ¡Conoce al Cursor<T> !

En la documentación puede ver que hay las siguientes implicaciones:

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>

A partir de esto, puede ver que puede usar el tipo Cursor<Vec<u8>> como un archivo ordinario , porque ¡ Read , Write y Seek están implementadas para ese tipo!

Pequeño ejemplo ( 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);

Para un ejemplo más útil, consulte la documentación vinculada anteriormente.


No necesitas un Cursor mayor parte del tiempo .

objeto que puedo dar a BufReader y BufWriter

BufReader requiere un valor que implemente Read :

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

BufWriter requiere un valor que implemente Write :

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

Si ve los implementadores de Read , encontrará impl<''a> Read for &''a [u8] .

Si ve los implementadores de Write , encontrará 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); }

Escribir a un Vec siempre se agregará al final. También tomamos una porción del Vec que podemos actualizar. Cada lectura de c avanzará el corte más y más hasta que esté vacío.

Las principales diferencias con el Cursor :

  • No puede buscar los datos, por lo que no puede volver a leerlos fácilmente
  • No se puede escribir en ninguna parte excepto al final

Si desea usar BufReader con una String en memoria, puede usar el método 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())); }

Esto imprime read_buff got Potato! . No hay necesidad de usar un cursor para este caso.

Para usar una String en memoria con BufWriter , puede usar el método as_mut_vec . Lamentablemente no es unsafe y no he encontrado ninguna otra manera. No me gusta el enfoque del Cursor ya que consume el vector y todavía no he encontrado una manera de usar el Cursor junto con BufWriter .

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); } }