Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the simplest way to pipe from a Read to a Write [duplicate]

Tags:

rust

I've got two objects. One implements the std::io::Read trait and the other implements the std::io::Write trait (e.g., two std::fs::File instances). I'm trying to figure out a simple and efficient way to pipe the data from the Read instance into the Write instance.

Let me add that I'm fully aware of std::fs::copy, but that only applies to files on a file system...these are not that. I also looked at std::io::copy, but it doesn't work with Read and Write instances.

I know that I can read the contents of the Read into a Vec<u8> with something like this:

let mut data = Vec::new();
file.read_to_end(&mut data);

But read_to_end fills a Vec<u8> but the corresponding function on Write, write_all, takes a &[u8] and I don't see any method on Vec<u8> that allows me to create a new array, only a slice of some pre-specified size.

I can imagine several different ways to do this (read/write one byte at a time, read/write chunks). But I am hoping that there is some function in std that does all this (with all the requisite error handling, chunk size management, etc) but if it is there, I haven't been able to find it.

Any suggestions on a simple way to do this? I am admittedly relatively new to Rust, but believe me when I say I spent quite a bit of time looking for such a thing and couldn't find it. Yes, I realize in that time I could have implemented but I wanted something that would be efficient and I'm concerned that what I would write wouldn't be optimal.

Thanks for any assistance.

like image 857
Michael Tiller Avatar asked Mar 29 '17 00:03

Michael Tiller


Video Answer


1 Answers

I also looked at std::io::copy, but it doesn't work with Read and Write instances.

It does. Look at the where clause in its signature:

pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64> 
where R: Read, W: Write

For instance, here I redirect stdin to stdout:

use std::io;

fn main() {
  let mut stdin = io::stdin();
  let mut stdout = io::stdout();
  io::copy(&mut stdin,&mut stdout);
}

If you are looking for a buffer to right into and read out of, BufStream from the bufstream crate should be of use.

I can imagine several different ways to do this (read/write one byte at a time, read/write chunks). But I am hoping that there is some function in std that does all this (with all the requisite error handling, chunk size management, etc) but if it is there, I haven't been able to find it.

That is exactly what std::io::copy does - it allocates a buffer and then loops between reading into that buffer and writing out from that buffer until there is nothing left to read.

like image 131
Alec Avatar answered Sep 22 '22 06:09

Alec