Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
467 views
in Technique[技术] by (71.8m points)

io - How to idiomatically / efficiently pipe data from Read+Seek to Write?

I want to take data from random locations in input file, and output them sequentially to output file. Preferably, with no unnecessary allocations.

This is one kind of solution I have figured out:

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

#[test]
fn read_write() {
    // let's say this is input file
    let mut input_file = Cursor::new(b"worldhello");
    // and this is output file
    let mut output_file = Vec::<u8>::new();

    assemble(&mut input_file, &mut output_file).unwrap();

    assert_eq!(b"helloworld", &output_file[..]);
}

// I want to take data from random locations in input file
// and output them sequentially to output file
pub fn assemble<I, O>(input: &mut I, output: &mut O) -> Result<(), io::Error> 
    where I: Read + Seek, O: Write 
{
    // first seek and output "hello"
    try!(input.seek(SeekFrom::Start(5)));
    let mut hello_buf = [0u8; 5];
    try!(input.take(5).read(&mut hello_buf));
    try!(output.write(&hello_buf));

    // then output "world"
    try!(input.seek(SeekFrom::Start(0)));
    let mut world_buf = [0u8; 5];
    try!(input.take(5).read(&mut world_buf));
    try!(output.write(&world_buf));

    Ok(())
}

Let's not worry about I/O latency here.

Questions:

  1. Does the stable Rust have some helper to take x bytes from one stream and push them to another stream? Or do I have to roll my own?
  2. If I have to roll my own, maybe there is a better way?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are looking for io::copy:

use std::io::{self, prelude::*, SeekFrom};

pub fn assemble<I, O>(mut input: I, mut output: O) -> Result<(), io::Error>
where
    I: Read + Seek,
    O: Write,
{
    // first seek and output "hello"
    input.seek(SeekFrom::Start(5))?;
    io::copy(&mut input.by_ref().take(5), &mut output)?;

    // then output "world"
    input.seek(SeekFrom::Start(0))?;
    io::copy(&mut input.take(5), &mut output)?;

    Ok(())
}

If you look at the implementation of io::copy, you can see that it's similar to your code. However, it takes care to handle more error cases:

  1. write does not always write everything you ask it to!
  2. An "interrupted" write isn't usually fatal.

It also uses a larger buffer size but still stack-allocates it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...