6

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.

Michael Tiller
  • 9,291
  • 3
  • 26
  • 41
  • 1
    "I also looked at `std::io::copy`, but it doesn't work with `Read` and `Write` instances." Huh? The type parameters `R` and `W` have bounds `R: Read` and `W: Write`, so it should work. – Francis Gagné Mar 29 '17 at 00:55
  • 1
    [`std::io::copy`](https://doc.rust-lang.org/std/io/fn.copy.html) should definitely work. Can you make an MCVE? – E_net4 Mar 29 '17 at 00:58
  • You are correct. I mistakenly read that as meaning that `reader` and `writer` had to have the `Sized` trait. My apologies, I should not have missed that. :-( – Michael Tiller Mar 29 '17 at 01:21

1 Answers1

13

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 write 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.

Cornelius Roemer
  • 3,772
  • 1
  • 24
  • 55
Alec
  • 31,829
  • 7
  • 67
  • 114
  • 1
    Thanks. First off, you are correct, of course. Also, your answer was useful because it helped me to realize why `std::io::copy` didn't work for me the first time which was that lack of `&mut` in front of the variable. The error message confused me, but your example helped me understand what it was trying to tell me. Thanks again. – Michael Tiller Mar 29 '17 at 01:23
  • Wait, why does `std::io::copy` take reader and writer args as mut in the first place? – infogulch Feb 06 '22 at 02:58
  • 1
    @infogulch because [`read` methods from `Read`](https://doc.rust-lang.org/std/io/trait.Read.html) and [`write` methods from `Write`](https://doc.rust-lang.org/std/io/trait.Write.html) both require `&mut self`. As for the why behind that, I'd say it is safe to say that most implementations of read and write will require some mutation. – Alec Feb 07 '22 at 13:20