Read & Write
Recipe | Crates | Categories |
---|---|---|
Read lines of strings from a file | ||
Avoid writing and reading from a same file | ||
Access a file randomly using a memory map |
Read lines of strings from a file
Writes a three-line message to a file, then reads it back a line at a time with the std::io::Lines
⮳ iterator created by
std::io::BufRead::lines
⮳ std::fs::File
⮳ implements std::io::Read
⮳ which provides std::io::BufReader
⮳ trait. std::fs::File::create
⮳ opens a std::fs::File
⮳ for writing, std::fs::File::open
⮳ for reading.
use std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::io::Error; use std::io::Write; fn main() -> Result<(), Error> { let path = "temp/lines.txt"; let mut output = File::create(path)?; write!(output, "Rust\n💖\nFun")?; let input = File::open(path)?; let buffered = BufReader::new(input); for line in buffered.lines() { println!("{}", line?); } Ok(()) }
Avoid writing and reading from the 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 std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::io::Error; use std::io::ErrorKind; use std::path::Path; use same_file::Handle; fn main() -> Result<(), Error> { std::fs::write("temp/new.txt", b"Lorem ipsum")?; let path_to_read = Path::new("temp/new.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
displays the contents of the file new.txt
.
cargo run >> new.txt
errors because the two files are same.
Access a file randomly using a memory map
Creates a memory map of a file using memmap2
⮳ and simulates some non-sequential reads from the file. Using a memory map means you just index into a slice rather than dealing with std::fs::File::seek
⮳ to navigate a std::fs::File
⮳.
The memmap2::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.
use std::fs::File; use std::io::Error; use std::io::Write; use memmap2::Mmap; fn main() -> Result<(), Error> { write!( File::create("temp/content.txt")?, "My hovercraft is full of eels!" )?; let file = File::open("temp/content.txt")?; let map = unsafe { Mmap::map(&file)? }; let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29]; assert_eq!(&map[3..13], b"hovercraft"); let random_bytes: Vec<u8> = random_indexes.iter().map(|&idx| map[idx]).collect(); assert_eq!(&random_bytes[..], b"My loaf!"); Ok(()) }