How do I read chunk by chunk from a type that implements Read?

Viewed 229

I need to read data into chunks of an exact size (the last chunk may be partially filled). Ideally, this method would also work for all types that are Read. My initial idea was something along the lines of:

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

const CHUNK_SIZE: usize = 2;

fn main() -> Result<(), Box<dyn error::Error>> {
    let mut a = &[1u8, 2, 3, 4, 5][..]; // Some Read type
    let mut buf = vec![0u8; CHUNK_SIZE];
    loop {
        match a.read_exact(&mut buf) {
            Ok(_) => println!("{:?}", buf),
            Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => break,
            Err(e) => return Err(e.into()),
        }
    }
    buf.clear();
    a.read_to_end(&mut buf)?;
    println!("{:?}", buf);
    Ok(())
}

This toy example works; however, reading the documentation for Read I can't seem to reason if it is correct. The documentation says that after a failed read_exact nothing can be assumed about the buffer contents. Will the read_to_end after a failed read_exact always retrieve those remaining bytes?

Is this code correct or is there a better way to read chunks?

1 Answers

If you want to be sure your chunked reads work, use read, not read_exact. read returns a Result<usize> with the number of bytes read, and 0 if it reaches an EOF. This will ensure that it works with partial data.

Related