#std::fs 模块
Rust 的 std::fs
模块提供了文件系统操作的工具,包括文件和目录的创建、读取、写入、删除和元数据访问等。它是标准库的一部分,用于处理本地文件系统任务。std::fs
的函数多返回 std::io::Result
以处理错误,如文件不存在或权限不足,确保安全性和显式错误处理。模块常与 std::path
和 std::io
结合使用。
1. std::fs 简介
- 导入:
use std::fs;
- 主要类型和函数:
- File:文件句柄,用于读写(从
std::fs::File
)。 - DirEntry:目录条目,用于读取目录。
- 函数:
read
/write
(字节)、read_to_string
/write
(字符串)、create_dir
/remove_dir
(目录)、metadata
(元数据)、copy
/rename
/remove_file
(文件操作)。
- File:文件句柄,用于读写(从
- 优势:跨平台(Windows/Unix 处理差异)、线程安全、集成 I/O trait。
- 注意:操作可能失败(返回 Result),如权限或路径无效。路径用
std::path::Path
以确保兼容。
2. 文件读写
std::fs
提供简单函数读取/写入整个文件。
示例:读取文件为字符串
use std::fs; fn main() -> std::io::Result<()> { let contents = fs::read_to_string("example.txt")?; println!("文件内容: {}", contents); Ok(()) }
- 解释:
read_to_string
读取整个文件为 String。如果文件不存在,返回 Err(io::Error { kind: NotFound })。用 ? 传播错误。类似:read
返回 Vec(字节)。
示例:写入文件
use std::fs; fn main() -> std::io::Result<()> { fs::write("output.txt", "Hello, Rust!")?; println!("文件已写入"); Ok(()) }
- 解释:
write
覆盖或创建文件,接受 &str 或 &[u8]。如果目录不存在,返回 Err。其他:OpenOptions
用于自定义打开模式(如追加)。
示例:使用 File 句柄读写
use std::fs::File; use std::io::{Read, Write}; fn main() -> std::io::Result<()> { let mut file = File::create("file.txt")?; file.write_all(b"一些字节")?; let mut contents = String::new(); let mut file = File::open("file.txt")?; file.read_to_string(&mut contents)?; println!("读取: {}", contents); Ok(()) }
- 解释:
File::create
创建/覆盖文件。File::open
只读打开。集成Read
和Write
trait。用于大文件时,考虑BufReader
/BufWriter
以缓冲。
3. 目录操作
管理目录创建、读取和删除。
示例:创建和删除目录
use std::fs; fn main() -> std::io::Result<()> { fs::create_dir("new_dir")?; // 创建单个目录 fs::create_dir_all("nested/dir/path")?; // 创建嵌套目录 fs::remove_dir("new_dir")?; // 删除空目录 fs::remove_dir_all("nested")?; // 递归删除 Ok(()) }
- 解释:
create_dir_all
创建中间目录。如果目录已存在,返回 Err(AlreadyExists)。remove_dir_all
危险,用于非空目录;小心使用。
示例:读取目录
use std::fs; fn main() -> std::io::Result<()> { let paths = fs::read_dir(".")?; // 当前目录 for path in paths { let entry = path?; println!("路径: {}, 类型: {:?}", entry.path().display(), entry.file_type()?); } Ok(()) }
- 解释:
read_dir
返回 DirEntry 迭代器。DirEntry
有path()
、metadata()
、file_type()
(FileType 如 is_dir())。处理迭代中的 Result。
4. 文件元数据和操作
访问文件信息和执行复制/重命名。
示例:文件元数据
use std::fs; fn main() -> std::io::Result<()> { let metadata = fs::metadata("example.txt")?; println!("大小: {} 字节", metadata.len()); println!("是文件?{}", metadata.is_file()); println!("修改时间: {:?}", metadata.modified()?); let permissions = metadata.permissions(); println!("只读?{}", permissions.readonly()); Ok(()) }
- 解释:
metadata
返回 Metadata。len()
文件大小。permissions()
返回 Permissions(readonly/set_readonly)。modified()
返回 SystemTime。
示例:复制、重命名和删除文件
use std::fs; fn main() -> std::io::Result<()> { fs::copy("source.txt", "dest.txt")?; // 复制 fs::rename("dest.txt", "new_name.txt")?; // 重命名/移动 fs::remove_file("new_name.txt")?; // 删除 Ok(()) }
- 解释:
copy
复制内容。rename
可跨目录(同分区)。remove_file
只删文件(非目录)。
5. 符号链接和硬链接
创建链接(Unix-like 系统支持更好)。
示例:创建符号链接
use std::fs; use std::os::unix::fs::symlink; // Unix 特定 #[cfg(unix)] fn main() -> std::io::Result<()> { symlink("original.txt", "link.txt")?; let target = fs::read_link("link.txt")?; println!("链接指向: {}", target.display()); Ok(()) }
- 解释:
symlink
创建软链接(Windows 用std::os::windows::fs::symlink_file
)。read_link
返回目标路径。hard_link
创建硬链接。用#[cfg]
条件编译平台特定代码。
6. 高级主题:OpenOptions 和 Canonicalize
- OpenOptions:自定义文件打开(如追加、只读)。
- canonicalize:解析绝对路径,展开链接。
示例:OpenOptions
use std::fs::OpenOptions; use std::io::Write; fn main() -> std::io::Result<()> { let mut file = OpenOptions::new() .write(true) .append(true) .create(true) .open("append.txt")?; file.write_all(b" 追加内容")?; Ok(()) }
- 解释:
OpenOptions
链式配置。append
追加模式。create
如果不存在创建。
示例:Canonicalize
use std::fs; fn main() -> std::io::Result<()> { let abs_path = fs::canonicalize("relative/path.txt")?; println!("绝对路径: {}", abs_path.display()); Ok(()) }
- 解释:
canonicalize
返回绝对 PathBuf,解析 ../ 和符号链接。
7. 最佳实践和常见陷阱
- 错误处理:总是用 ? 或 match 处理 Result(如 NotFound、PermissionDenied)。
- 路径:用
Path::new
创建路径,避免硬编码分隔符(/ vs \)。 - 安全性:避免用户输入路径(路径注入);用
canonicalize
规范化。 - 性能:大文件用 BufReader/Writer;目录迭代用 read_dir 而非递归。
- 跨平台:测试 Windows/Unix;符号链接在 Windows 需管理员权限。
- 常见错误:
- 文件不存在:Err(NotFound) – 检查前用 Path::exists()。
- 权限:Err(PermissionDenied) – 运行时检查。
- 非空目录删除:remove_dir 失败,用 remove_dir_all。
- 与 walkdir crate:复杂遍历用外部 crate。
- 线程:fs 操作线程安全,但并发写入需锁。
练习建议
- 编写工具:复制目录树,用 read_dir 递归。
- 创建日志函数:用 OpenOptions 追加写入文件。
- 检查文件修改:用 metadata 比较时间。