Standard Input and Output

BufReader

std::io::BufReader<R> is a generic struct that wraps any type R: Read (such as std::fs::File or std::net::TcpStream), adding an internal heap-allocated byte buffer (8 KiB = 8,192 bytes by default) and implementing both Read and BufRead.

Key Constructors and Methods on BufReader<R>

Method Signature Behavior
BufReader::new(inner) pub fn new(inner: R) -> BufReader<R> Wraps inner with the default 8,192-byte buffer capacity
BufReader::with_capacity(cap, inner) pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> Wraps inner with a custom buffer size (e.g., 64 * 1024 for large sequential file scans)
.get_ref(&self) pub fn get_ref(&self) -> &R Borrows the underlying reader R
.get_mut(&mut self) pub fn get_mut(&mut self) -> &mut R Mutably borrows the underlying reader R
.buffer(&self) pub fn buffer(&self) -> &[u8] Returns the slice of bytes currently buffered in memory and not yet consumed
.capacity(&self) pub fn capacity(&self) -> usize Returns the total allocated byte capacity of the internal buffer
.into_inner(self) pub fn into_inner(self) -> R Unwraps and returns R (Warning: discards any unread bytes currently sitting in .buffer()!)
.seek_relative(offset) pub fn seek_relative(&mut self, offset: i64) -> Result<()> (where R: Seek) Seeks within the existing memory buffer if offset lands inside .buffer(), avoiding an OS lseek syscall!

Reading a File Line by Line with BufReader::new(file)

use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Write};

fn main() -> io::Result<()> {
    let path = std::env::temp_dir().join("rust_ch49_bufreader_demo.txt");

    {
        let mut f = File::create(&path)?;
        writeln!(f, "100")?;
        writeln!(f, "250")?;
        writeln!(f, "400")?;
    }

    let file = File::open(&path)?;
    // Wrap `File` in `BufReader` (64 KiB custom capacity):
    let reader = BufReader::with_capacity(64 * 1024, file);

    let mut sum: i64 = 0;
    for line in reader.lines() {
        let num: i64 = line?.trim().parse().unwrap();
        sum += num;
    }

    fs::remove_file(&path)?;
    println!("sum of lines read via BufReader: {}", sum);
    Ok(())
}
sum of lines read via BufReader: 750

Caution When Calling .into_inner() or .get_mut() on a BufReader

Because BufReader reads ahead from the underlying R in 8 KiB chunks, the underlying File or TcpStream cursor is usually ahead of the logical BufReader cursor by reader.buffer().len() bytes!

  • If you read a header with BufReader and then call let raw_stream = reader.into_inner();, any payload bytes that were already pulled into reader.buffer() during the header read will be lost! Keep using the BufReader (or read reader.buffer() before calling .into_inner()).