文件系统操作

std::fs 模块包含多个用于处理文件系统的函数。

use std::fs; use std::fs::{File, OpenOptions}; use std::io; use std::io::prelude::*; #[cfg(target_family = "unix")] use std::os::unix; #[cfg(target_family = "windows")] use std::os::windows; use std::path::Path; // `% 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), } } // `% echo s > path` 命令的简单实现 fn echo(s: &str, path: &Path) -> io::Result<()> { let mut f = File::create(path)?; f.write_all(s.as_bytes()) } // `% touch path` 命令的简单实现(忽略已存在的文件) 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`"); // 创建目录,返回 `io::Result<()>` match fs::create_dir("a") { Err(why) => println!("! {:?}", why.kind()), Ok(_) => {}, } println!("`echo hello > a/b.txt`"); // 可以使用 `unwrap_or_else` 方法简化之前的匹配 echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| { println!("! {:?}", why.kind()); }); println!("`mkdir -p a/c/d`"); // 递归创建目录,返回 `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`"); // 创建符号链接,返回 `io::Result<()>` #[cfg(target_family = "unix")] { unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| { println!("! {:?}", why.kind()); }); } #[cfg(target_family = "windows")] { windows::fs::symlink_file("../b.txt", "a/c/b.txt").unwrap_or_else(|why| { println!("! {:?}", why.to_string()); }); } 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`"); // 读取目录内容,返回 `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`"); // 删除文件,返回 `io::Result<()>` fs::remove_file("a/c/e.txt").unwrap_or_else(|why| { println!("! {:?}", why.kind()); }); println!("`rmdir a/c/d`"); // 删除空目录,返回 `io::Result<()>` fs::remove_dir("a/c/d").unwrap_or_else(|why| { println!("! {:?}", why.kind()); }); }

以下是预期的成功输出:

$ 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`

最终 a 目录的状态如下:

$ tree a a |-- b.txt `-- c `-- b.txt -> ../b.txt 1 directory, 2 files

另一种定义 cat 函数的方法是使用 ? 运算符:

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) }

另请参阅:

cfg!