CodeBlanks Logo Icon CodeBlanks

BufReader

Read line by line efficiently with BufReader.

BufReader

To read large files line by line instead of loading them fully into memory, BufReader and BufRead::lines are used. Each line is a separate io::Result<String>:

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

let f = File::open("sayilar.txt")?;
for satir in BufReader::new(f).lines() {
    let satir = satir?;
    println!("{satir}");
}

lines() strips line endings (\n, \r\n) automatically. The BufRead trait must be in scope.

Separating bad lines

In real files some lines may be broken. Handling a read error with ? and a content error with match separately is a good habit:

let mut toplam = 0;
let mut hatali = 0;
for satir in BufReader::new(f).lines() {
    match satir?.trim().parse::<i32>() {
        Ok(n) => toplam += n,
        Err(_) => hatali += 1,
    }
}

Practice Sum the lines

Write a file containing "3\n5\n x \n7\n" in the temp folder. Read it line by line with BufReader; sum the parseable lines, count the others and print toplam 15, hatalı 1.

Starter code

main.rs
use std::env;
use std::fs::{self, File};
use std::io::{self, BufRead, BufReader};

fn main() {
    // buraya yaz
}

Sample solution

main.rs
use std::env;
use std::fs::{self, File};
use std::io::{self, BufRead, BufReader};

fn main() -> io::Result<()> {
    let yol = env::temp_dir().join("veri.txt");
    fs::write(&yol, "3\n5\n x \n7\n")?;
    let f = File::open(&yol)?;
    let mut toplam = 0;
    let mut hatali = 0;
    for s in BufReader::new(f).lines() {
        match s?.trim().parse::<i32>() {
            Ok(n) => toplam += n,
            Err(_) => hatali += 1,
        }
    }
    println!("toplam {}, hatalı {}", toplam, hatali);
    Ok(())
}

Expected output

toplam 15, hatalı 1

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 When is <code>BufReader::lines</code> preferred over <code>read_to_string</code>?

  • When the file is very large or lines are processed as a stream Correct answer
  • When the file is small
  • For binary files
  • Never

Explanation: lines keeps one line in memory at a time; even gigabyte logs can be processed with constant memory.

2 Line by line

Question
for satir in BufReader::new(f).____() {
    let satir = satir?;
}
Answer
for satir in BufReader::new(f).lines() {
    let satir = satir?;
}

Explanation: BufRead::lines yields each line as io::Result<String>.

3 Type and role

Term Meaning
BufReader<File> Buffered reading
BufRead The lines() trait
s? Read error
match on parse Content error

All lessons in Intermediate