文件系统操作

std::io::fs 模块包含几个处理文件系统的函数。

  1. use std::fs;
  2. use std::fs::{File, OpenOptions};
  3. use std::io;
  4. use std::io::prelude::*;
  5. use std::os::unix;
  6. use std::path::Path;
  7. // `% cat path` 的简单实现
  8. fn cat(path: &Path) -> io::Result<String> {
  9. let mut f = try!(File::open(path));
  10. let mut s = String::new();
  11. match f.read_to_string(&mut s) {
  12. Ok(_) => Ok(s),
  13. Err(e) => Err(e),
  14. }
  15. }
  16. // `% echo s > path` 的简单实现
  17. fn echo(s: &str, path: &Path) -> io::Result<()> {
  18. let mut f = try!(File::create(path));
  19. f.write_all(s.as_bytes())
  20. }
  21. // `% touch path`(忽略已存在文件)的简单实现
  22. fn touch(path: &Path) -> io::Result<()> {
  23. match OpenOptions::new().create(true).write(true).open(path) {
  24. Ok(_) => Ok(()),
  25. Err(e) => Err(e),
  26. }
  27. }
  28. fn main() {
  29. println!("`mkdir a`");
  30. // 创建一个目录,返回 `io::Result<()>`
  31. match fs::create_dir("a") {
  32. Err(why) => println!("! {:?}", why.kind()),
  33. Ok(_) => {},
  34. }
  35. println!("`echo hello > a/b.txt`");
  36. // 前面的匹配可以用 `unwrap_or_else` 方法简化
  37. echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
  38. println!("! {:?}", why.kind());
  39. });
  40. println!("`mkdir -p a/c/d`");
  41. // 递归创建一个目录,返回 `io::Result<()>`
  42. fs::create_dir_all("a/c/d").unwrap_or_else(|why| {
  43. println!("! {:?}", why.kind());
  44. });
  45. println!("`touch a/c/e.txt`");
  46. touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
  47. println!("! {:?}", why.kind());
  48. });
  49. println!("`ln -s ../b.txt a/c/b.txt`");
  50. // 创建一个符号链接,返回 `io::Resutl<()>`
  51. if cfg!(target_family = "unix") {
  52. unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| {
  53. println!("! {:?}", why.kind());
  54. });
  55. }
  56. println!("`cat a/c/b.txt`");
  57. match cat(&Path::new("a/c/b.txt")) {
  58. Err(why) => println!("! {:?}", why.kind()),
  59. Ok(s) => println!("> {}", s),
  60. }
  61. println!("`ls a`");
  62. // 读取目录的内容,返回 `io::Result<Vec<Path>>`
  63. match fs::read_dir("a") {
  64. Err(why) => println!("! {:?}", why.kind()),
  65. Ok(paths) => for path in paths {
  66. println!("> {:?}", path.unwrap().path());
  67. },
  68. }
  69. println!("`rm a/c/e.txt`");
  70. // 删除一个文件,返回 `io::Result<()>`
  71. fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {
  72. println!("! {:?}", why.kind());
  73. });
  74. println!("`rmdir a/c/d`");
  75. // 移除一个空目录,返回 `io::Result<()>`
  76. fs::remove_dir("a/c/d").unwrap_or_else(|why| {
  77. println!("! {:?}", why.kind());
  78. });
  79. }

下面是预期成功的输出:

  1. $ rustc fs.rs && ./fs
  2. `mkdir a`
  3. `echo hello > a/b.txt`
  4. `mkdir -p a/c/d`
  5. `touch a/c/e.txt`
  6. `ln -s ../b.txt a/c/b.txt`
  7. `cat a/c/b.txt`
  8. > hello
  9. `ls a`
  10. > a/b.txt
  11. > a/c
  12. `walk a`
  13. > a/c
  14. > a/c/b.txt
  15. > a/c/e.txt
  16. > a/c/d
  17. > a/b.txt
  18. `rm a/c/e.txt`
  19. `rmdir a/c/d`

a 目录的最终状态为:

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

另一种定义 cat 函数的方式是使用 ? 标记:

  1. fn cat(path: &Path) -> io::Result<String> {
  2. let mut f = File::open(path)?;
  3. let mut s = String::new();
  4. f.read_to_string(&mut s)?;
  5. Ok(s)
  6. }

参见:

cfg!