File System Operations
File.open()
std::fs::File::open(path) opens an existing file on the filesystem in read-only mode and returns io::Result<File>. It is a shorthand for OpenOptions::new().read(true).open(path).
Behavior and Error Conditions of File::open
File::open(path)
|
+-- File exists & readable ---> Returns `Ok(File)` positioned at byte offset `0`
| (Read-only: calling `.write()` on this `File` fails!)
+-- File does not exist ------> Returns `Err(io::Error)` with `ErrorKind::NotFound`
+-- Insufficient permissions -> Returns `Err(io::Error)` with `ErrorKind::PermissionDenied`
| Property | File::open(path) Behavior |
|---|---|
| Access mode | Read-only (O_RDONLY on Unix, GENERIC_READ on Windows) |
| Creates missing file? | No (returns ErrorKind::NotFound) |
| Truncates existing file? | No |
| Initial cursor offset | 0 (start of file) |
Descriptor inheritance across Command exec |
Opened with O_CLOEXEC / non-inheritable handle by default so child processes do not leak descriptors |
Distinguishing ErrorKind::NotFound from Other Open Errors
When opening a configuration or cache file that may not exist on first run, match on err.kind() == io::ErrorKind::NotFound to supply a default value while still propagating permission or I/O errors:
use std::fs::{self, File};
use std::io::{self, ErrorKind, Read};
use std::path::Path;
fn read_optional_file(path: &Path) -> io::Result<Option<String>> {
match File::open(path) {
Ok(mut file) => {
let mut text = String::new();
file.read_to_string(&mut text)?;
Ok(Some(text))
}
Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
Err(err) => Err(err),
}
}
fn main() -> io::Result<()> {
let missing = std::env::temp_dir().join("rust_ch50_nonexistent_12345.txt");
let existing = std::env::temp_dir().join("rust_ch50_existing.txt");
fs::write(&existing, "found=true")?;
println!("missing file: {:?}", read_optional_file(&missing)?);
println!("existing file: {:?}", read_optional_file(&existing)?);
fs::remove_file(&existing)?;
Ok(())
}
missing file: None
existing file: Some("found=true")
Relative Paths Are Resolved Against the Process's Current Working Directory
Passing a relative path like File::open("data/input.csv") resolves the path relative to std::env::current_dir() (the working directory from which the process was launched)—not the directory containing the compiled binary or the .rs source file.