Read & Write from Files
Recipe | Crates | Categories |
---|---|---|
Read Lines of Strings from a File | ||
Avoid Writing and Reading from the 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.
//! Demonstrates writing to and reading from a file. use std::fs; 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"; // Create a file if it does not exist, and will truncate it if it does. let mut output = File::create(path)?; // Write to the file. write!(&mut output, "Rust\n💖\nFun")?; // Open the file for reading. let input = File::open(path)?; // Adds buffering. let buffered = BufReader::new(input); // Iterate over the lines of this reader. 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.
//! This example demonstrates how to check whether two file paths refer to the //! same file or directory. use std::fs; 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; /// Check whether we are reading & writing to the same file. fn main() -> Result<(), Error> { // Get a Handle for the standard output. let stdout_handle = Handle::stdout()?; // Get a Handle for the file we want to read. let path_to_read = Path::new("temp/new.txt"); let handle = Handle::from_path(path_to_read)?; // Check if the file handle is the same as the standard output handle. if stdout_handle == handle { return Err(Error::new( ErrorKind::Other, "You are reading and writing to the same file!", )); } else { // Print the contents of the file. 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.
//! Demonstrates reading from a memory-mapped file. use std::fs; 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!" )?; // Open the file for reading. let file = File::open("temp/content.txt")?; // Create a memory map of the file. This is unsafe because it relies on the // file not being modified externally. let map = unsafe { Mmap::map(&file)? }; // Print the memory map (for debugging purposes). println!("{:?}", map); // Define some random indexes into the memory map. let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29]; // Assert that a slice of the memory map matches the expected bytes. assert_eq!(&map[3..13], b"hovercraft"); // Collect bytes from the memory map at the random indexes. let random_bytes: Vec<u8> = random_indexes.iter().map(|&idx| map[idx]).collect(); assert_eq!(&random_bytes[..], b"My loaf!"); Ok(()) }