2016-12-09 1 views
12

Мне нужен полностью закрытый объект, который я могу дать BufReader и BufWriter. Что-то вроде Python's StringIO. Я хочу писать и читать с такого объекта, используя методы, обычно используемые с File.Как создать объект в памяти, который может использоваться как Reader или Writer в Rust?

Есть ли способ сделать это, используя стандартную библиотеку?

ответ

13

На самом деле есть способ. Знакомьтесь: Cursor<T>!

В документации вы можете увидеть, что существуют следующие 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<Vec<u8>> так же, как обычный файл, потому что Read, Write и Seek реализованы для этого типа!

Маленький пример (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); 

Для более полезной, например, проверить документацию, связанную выше.

1

Если вы хотите использовать 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!. Нет необходимости использовать курсор для этого случая.

Для использования в памяти String с BufWriter, вы можете использовать метод as_mut_vec. К сожалению, это unsafe, и я не нашел другого способа. Мне не нравится подход Cursor, так как он потребляет вектор, и я еще не нашел способ использовать Cursor вместе с 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); 
    } 
} 
+0

Вы можете [Получить 'Vec' назад] (https://doc.rust-lang.org/std/io/struct.Cursor.html#method.into_inner) после того, как вы сделали с' Cursor'. – Shepmaster

+0

@Shepmaster Отлично! И затем я могу использовать ['from_utf8'] (https://doc.rust-lang.org/std/str/fn.from_utf8.html) для свертывания в String,' from_utf8', кажется, не копирует вектор так, чтобы он должен быть эффективен, можно также использовать 'from_utf8_unchecked ', который должен быть простым. –

Смежные вопросы