Rust 文件操作 - 读、写、删、查询属性
Rust 中主要围绕 std::fs::File
与 std::path::{Path, PathBuf}
来实现文件相关的操作,前者完成文件创建与读写删等操作,后者完成文件路径的构造。
跟随本文流程操作一遍,就可以较好的掌握相关内容。
编写本文时,笔者使用的 Rust 版本为 1.79.0。
要操作文件,就先构造一个可用的路径
std::path::PathBuf
与std::path::Path
这俩都是用于构造文件路径的,开发中选取其中适合的一个即可。两者区别在于 PathBuf
构造的是可变路径,可以在后续通过 push()
来不断扩展路径,push()
会自动完成路径的拼接。
use std::path::PathBuf;
// 先构造路径缓存
let mut path = PathBuf::new();
// 后续补全整个路径
path.push(r"C:\");
path.push("windows");
path.push("system32");
// 这里官方示例使用 set_extension() 但实际上,在最后一次的 push 中,我们直接写 system32.dll
// 也是一样的效果
path.set_extension("dll");
// 最终路径: C:\\windows\\system32.dll
而 Path 需要在 new() 环节就确定整个完整的路径且不可再变。
use std::path::Path;
use std::ffi::OsStr;
// Note: this example does work on Windows
let path = Path::new("./foo/bar.txt");
let parent = path.parent();
assert_eq!(parent, Some(Path::new("./foo")));
let file_stem = path.file_stem();
assert_eq!(file_stem, Some(OsStr::new("bar")));
let extension = path.extension();
assert_eq!(extension, Some(OsStr::new("txt")));
只构造路径是无用的,我们还需要把路径“喂给”下面这位才可以实现文件的创建。
路径可用,我们开始操作文件
std::fs::File::create()
才是真正在干活的
File::create() 需要接收一个路径,可以是 String 或 &str、PathBuf、Path 等 ,返回 Result,可以通过 unwrap() 取出 File
结构,File 结构是我们操控文件的“句柄”。
// main.rs
use std::fs::File;
use std::path::Path;
let save_path = Path::new(r"D:\code\rustProject\file_test\src\test.txt");
// 上边的代码你也可以写成
// let mut save_path = PathBuf::new();
// save_path.push(r"D:\code\rustProject\file_test\src");
// save_path.push("test.txt");
// 最终效果都是一致的
let mut file_handle = File::create(save_path).unwrap();
现在我们拿到了操作文件的“句柄”,那么可以开始操作文件了
写操作
如果需要写入 bytes
,如下载文件,则根据官方示例使用 Write trait 下的 write_all
方法。
// main.rs
use std::io::prelude::*;
use std::fs::File;
fn main() -> std::io::Result<()> {
let mut buffer = File::create("foo.txt")?;
buffer.write_all(b"some bytes")?;
Ok(())
}
如果需要写入文本
,如保存输入,则根据官方示例使用 write!()
宏。
// main.rs
use std::fs::File;
use std::path::Path;
// use std::path::PathBuf;
use std::io::Write; // write!() 宏使用了该 Trait,遵循 Rust 语法(孤儿规则)必须引入该 Trait
fn main() {
let save_path = Path::new(r"D:\code\rustProject\file_test\src\test.txt");
// let mut save_path = PathBuf::new();
// save_path.push(r"D:\code\rustProject\file_test\src");
// save_path.push("test.txt");
let mut file_handle = File::create(save_path).unwrap();
write!(file_handle, "oh, My dear Rust~").unwrap();
}
上边的代码实现了在 D:\code\rustProject\file_test\src
位置下创建名为 test.txt
的文件,并写入内容 oh, My dear Rust~
。
注意!该创建文件的方式是覆盖式的,如果文件已经存在则会将文件内容完全抹去,再重头写入文本,如果你不想这样的话,你可以使用
File::create_new()
方法,该方法在创建文件时,如果遇到文件已存在的情况,会抛出AlreadyExists
错误,具体请在编辑器中跳转至对应源码注释查看。
接下来我们尝试从 test.txt
中读取改文字并打印至控制台。
读操作
读取操作也是很简单的,通过 File::open()
打开我们刚才生成的文件再读取其内容即可,我们直接看代码。
use std::fs::File;
use std::path::Path;
use std::io::{Read, Write};
fn main() {
// 文件路径构造
let save_path = Path::new(r"D:\code\rustProject\file_test\src\test.txt");
// 生成文件
let mut file_handle = File::create(save_path).unwrap();
write!(file_handle, "oh, My dear Rust~").unwrap();
// 开始读取文件
file_handle = File::open(save_path).unwrap();
let mut text = String::new(); // 作为容纳读取结果的容器
file_handle.read_to_string(&mut text).expect("读取失败"); // 读取文件内容
println!("{text}"); // 打印出文件内容
}
最终输出结果:oh, My dear Rust~
,读取文件成功。
删操作
在 Rust 中,我们可以通过 std::fs::remove_file()
方法来实现文件的删除。
实现代码如下,我们将在打印出文件内容后删除该文件。
注意!该删除方式会直接移除文件,不会将其移至回收站!
use std::fs::{File, remove_file};
use std::path::Path;
use std::io::{Read, Write}; // 这里新引入了 Read Trait,因为 read_to_string() 方法
fn main() {
let save_path = Path::new(r"D:\code\rustProject\file_test\src\test.txt");
let mut file_handle = File::create(save_path).unwrap();
write!(file_handle, "oh, My dear Rust~").unwrap();
file_handle = File::open(save_path).unwrap();
let mut text = String::new(); // 作为容纳读取结果的容器
file_handle.read_to_string(&mut text).expect("读取失败"); // 读取文件内容
println!("{text}"); // 打印出文件内
remove_file(save_path).unwrap() // 仅此一行,删除 save_path 指定的文件
}
查询文件属性
文件自身是具有属性的,有时我们需要获取这些文件属性来进行下一步操作,必要时我们也可能回去修改它,如将文件变为仅允许读写。
我们直接看代码:
use std::time::SystemTime; // 用于获取现在的系统时间
use std::fs::{File, remove_file};
use std::path::Path;
use std::io::{Read, Write};
fn main() {
let save_path = Path::new(r"D:\code\rustProject\file_test\src\test.txt");
let mut file_handle = File::create(save_path).unwrap();
write!(file_handle, "oh, My dear Rust~").unwrap();
let mut file_handle = File::open(save_path).unwrap();
let mut text = String::new(); // 作为容纳读取结果的容器
file_handle.read_to_string(&mut text).expect("读取失败"); // 读取文件内容
println!("{text}"); // 打印出文件内
println!("文件属性如下:");
println!("因为我们在对刚生成的文件进行属性获取,牵涉时间的地方可能会得到 µs 级的信息!!!");
// 单位可以自己换算,返回的是 bytes
println!("文件大小:{:?} Bytes", file_handle.metadata().unwrap().len());
// 在计算机中,文件夹也是一种文件,因此也可以使用上边的方法创建目录
println!("该文件是不是文件夹这种特殊文件:{:?}", file_handle.metadata().unwrap().is_dir());
// 这里意在获取文件权限,但目前 rust 标准库(rustc 1.79.0) 只支持获取文件是否可读。期待 rust 的进一步发展
println!("该文件是否为只读:{:?}", file_handle.metadata().unwrap().permissions().readonly());
// 创建的时间距现在多久
println!("该文件创建的时间:{:?}", file_handle.metadata().unwrap().created().unwrap().duration_since(SystemTime::now()));
// 最后修改距现在多久
println!("最后一次修改时间距现在过去了:{:?}", file_handle.metadata().unwrap().modified().unwrap().duration_since(SystemTime::now()));
// 最后访问距现在多久
println!("最后一次访问的时间距现在过去了:{:?}", file_handle.metadata().unwrap().accessed().unwrap().duration_since(SystemTime::now()));
remove_file(save_path).unwrap(); // 仅此一行
}
以上便是 Rust 1.79.0 全部可以直接获取的文件属性,可见,目前 rust 标准库对于文件属性获取方面还存在不足,可以直接获取的信息不多,但毕竟 rust 还年轻,请再多给它一些时间!