Read & Write

Read lines of strings from a file

std-badge cat-filesystem-badge

Writes a three-line message to a file, then reads it back a line at a time with the Lines iterator created by BufRead::lines. File implements Read which provides BufReader trait. File::create opens a File for writing, File::open for reading.

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

fn main() -> Result<(), Error> {
    let path = "lines.txt";

    let mut output = File::create(path)?;
    write!(output, "Rust\nšŸ’–\nFun\n")?;

    let input = File::open(path)?;
    let buffered = BufReader::new(input);

    for line in buffered.lines() {
        println!("{}", line?);
    }

    Ok(())
}

Buffered reading / writing is usually more efficient and faster than regular input / output operations.

Avoid writing and reading from a same file

same_file-badge cat-filesystem-badge

Add this crate to your own project:

cargo add same_file

Use same_file::Handle to a file that can be tested for equality with other handles. In this example, the handles of file to be read from and to be written to are tested for equality.

use same_file::Handle;
use std::fs::File;
use std::io::{BufRead, BufReader, Error, ErrorKind};
use std::path::Path;

fn main() -> Result<(), Error> {
    let path_to_read = Path::new("content.txt");

    let stdout_handle = Handle::stdout()?;
    let handle = Handle::from_path(path_to_read)?;

    if stdout_handle == handle {
        return Err(Error::new(
            ErrorKind::Other,
            "You are reading and writing to the same file",
        ));
    } else {
        let file = File::open(&path_to_read)?;
        let file = BufReader::new(file);
        for (num, line) in file.lines().enumerate() {
            println!("{} : {}", num, line?.to_uppercase());
        }
    }

    Ok(())
}
cargo run --example same-file

displays the contents of the file content.txt.

cargo run --example same-file >> ./content.txt

errors because the two files are same.

Access a file randomly using a memory map

memmap-badge cat-filesystem-badge

Add the memmap2 crate to your own project:

cargo add memmap2

Creates a memory map of a file using memmap and simulates some non-sequential reads from the file. Using a memory map means you just index into a slice rather than dealing with seek to navigate a File.

The Mmap::map function assumes the file behind the memory map is not being modified at the same time by another process or else a race condition occurs. This is why it needs to be enclosed in an unsafe block.

use memmap2::Mmap;
use std::fs::File;
use std::io::{Write, Error};

fn main() -> Result<(), Error> {
    write!(File::create("content.txt")?, "My hovercraft is full of eels!")?;

    let file = File::open("content.txt")?;
    let map = unsafe { Mmap::map(&file)? };

    assert_eq!(&map[3..13], b"hovercraft");

    let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29];
    let random_bytes: Vec<u8> = random_indexes.iter()
        .map(|&idx| map[idx])
        .collect();
    assert_eq!(&random_bytes[..], b"My loaf!");

    Ok(())
}