diff options
Diffstat (limited to 'src/doc/rust-by-example/src/std_misc/fs.md')
-rw-r--r-- | src/doc/rust-by-example/src/std_misc/fs.md | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/doc/rust-by-example/src/std_misc/fs.md b/src/doc/rust-by-example/src/std_misc/fs.md new file mode 100644 index 000000000..48e4d4d66 --- /dev/null +++ b/src/doc/rust-by-example/src/std_misc/fs.md @@ -0,0 +1,146 @@ +# Filesystem Operations + +The `std::fs` module contains several functions that deal with the filesystem. + +```rust,ignore +use std::fs; +use std::fs::{File, OpenOptions}; +use std::io; +use std::io::prelude::*; +use std::os::unix; +use std::path::Path; + +// A simple implementation of `% cat path` +fn cat(path: &Path) -> io::Result<String> { + let mut f = File::open(path)?; + let mut s = String::new(); + match f.read_to_string(&mut s) { + Ok(_) => Ok(s), + Err(e) => Err(e), + } +} + +// A simple implementation of `% echo s > path` +fn echo(s: &str, path: &Path) -> io::Result<()> { + let mut f = File::create(path)?; + + f.write_all(s.as_bytes()) +} + +// A simple implementation of `% touch path` (ignores existing files) +fn touch(path: &Path) -> io::Result<()> { + match OpenOptions::new().create(true).write(true).open(path) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} + +fn main() { + println!("`mkdir a`"); + // Create a directory, returns `io::Result<()>` + match fs::create_dir("a") { + Err(why) => println!("! {:?}", why.kind()), + Ok(_) => {}, + } + + println!("`echo hello > a/b.txt`"); + // The previous match can be simplified using the `unwrap_or_else` method + echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); + + println!("`mkdir -p a/c/d`"); + // Recursively create a directory, returns `io::Result<()>` + fs::create_dir_all("a/c/d").unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); + + println!("`touch a/c/e.txt`"); + touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); + + println!("`ln -s ../b.txt a/c/b.txt`"); + // Create a symbolic link, returns `io::Result<()>` + if cfg!(target_family = "unix") { + unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); + } + + println!("`cat a/c/b.txt`"); + match cat(&Path::new("a/c/b.txt")) { + Err(why) => println!("! {:?}", why.kind()), + Ok(s) => println!("> {}", s), + } + + println!("`ls a`"); + // Read the contents of a directory, returns `io::Result<Vec<Path>>` + match fs::read_dir("a") { + Err(why) => println!("! {:?}", why.kind()), + Ok(paths) => for path in paths { + println!("> {:?}", path.unwrap().path()); + }, + } + + println!("`rm a/c/e.txt`"); + // Remove a file, returns `io::Result<()>` + fs::remove_file("a/c/e.txt").unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); + + println!("`rmdir a/c/d`"); + // Remove an empty directory, returns `io::Result<()>` + fs::remove_dir("a/c/d").unwrap_or_else(|why| { + println!("! {:?}", why.kind()); + }); +} + +``` + +Here's the expected successful output: + +```shell +$ rustc fs.rs && ./fs +`mkdir a` +`echo hello > a/b.txt` +`mkdir -p a/c/d` +`touch a/c/e.txt` +`ln -s ../b.txt a/c/b.txt` +`cat a/c/b.txt` +> hello +`ls a` +> "a/b.txt" +> "a/c" +`rm a/c/e.txt` +`rmdir a/c/d` +``` + +And the final state of the `a` directory is: + +```shell +$ tree a +a +|-- b.txt +`-- c + `-- b.txt -> ../b.txt + +1 directory, 2 files +``` + +An alternative way to define the function `cat` is with `?` notation: + +```rust,ignore +fn cat(path: &Path) -> io::Result<String> { + let mut f = File::open(path)?; + let mut s = String::new(); + f.read_to_string(&mut s)?; + Ok(s) +} +``` + +### See also: + +[`cfg!`][cfg] + +[cfg]: ../attribute/cfg.md |