Essential Standard Traits

Read and Write

The Read and Write traits in std::io provide byte-oriented synchronous input and output across files, TCP sockets, standard streams, and in-memory byte buffers.

Trait Definitions

pub trait Read {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;

    // Provided methods:
    // read_exact, read_to_end, read_to_string, bytes, chain, take, ...
}

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize>;
    fn flush(&mut self) -> std::io::Result<()>;

    // Provided methods:
    // write_all, write_fmt, by_ref, ...
}
  • Read::read pulls up to buf.len() bytes into buf and returns Ok(n) indicating how many bytes were read (Ok(0) signals end-of-file when buf is non-empty).
  • Write::write writes a prefix of buf and returns Ok(n) bytes written; write_all loops until the entire slice is written.

Standard Types Implementing Read and Write

Type Implements Read? Implements Write? Notes
std::fs::File Yes Yes Unbuffered OS file descriptor/handle
std::net::TcpStream Yes Yes Unbuffered network socket
&[u8] (byte slice) Yes No Reads from the slice and advances it in place
Vec<u8> No Yes Appends written bytes to the end of the vector
std::io::Cursor<T> Yes (if T: AsRef<[u8]>) Yes (for Vec<u8>, &mut [u8]) Adds a seekable position cursor to in-memory buffers
BufReader<R> / BufWriter<W> BufReader<R> BufWriter<W> Wraps any Read or Write with an in-memory buffer to reduce syscalls

Writing Testable I/O Code with Generic Read and Write

Accepting impl Read and impl Write instead of concrete File or TcpStream types lets you test I/O logic entirely in memory using &[u8] and Vec<u8>:

use std::io::{self, Read, Write};

fn copy_uppercase(mut reader: impl Read, mut writer: impl Write) -> io::Result<usize> {
    let mut content = String::new();
    reader.read_to_string(&mut content)?;

    let upper = content.to_uppercase();
    writer.write_all(upper.as_bytes())?;
    writer.flush()?;
    Ok(upper.len())
}

fn main() -> io::Result<()> {
    let input: &[u8] = b"rust io traits";
    let mut output: Vec<u8> = Vec::new();

    let written = copy_uppercase(input, &mut output)?;
    println!("Bytes written: {written}");
    println!("Output text:   {}", String::from_utf8_lossy(&output));
    Ok(())
}
Bytes written: 14
Output text:   RUST IO TRAITS