说在前面
- rust新手,egui没啥找到啥教程,这里自己记录下学习过程
- 环境:windows11 22H2
- rust版本:rustc 1.71.1
- egui版本:0.22.0
- eframe版本:0.22.0
- 上一篇:这里
rfd-Rusty File Dialogs
- 一个跨平台的本地文件选择库,支持的平台:
- Windows
- macOS
- Linux & BSDs (GTK3 or XDG Desktop Portal)
- WASM32 (async only)
- 让我们来看看使用:
if ui.button("open file").clicked() { if let Some(path) = rfd::FileDialog::new().pick_file() { self.picked_path = Some(path.display().to_string()); } }
- 还可以添加文件后缀筛选:
if ui.button("open file").clicked() { if let Some(path) = rfd::FileDialog::new().add_filter("text", &["txt", "rs"]).pick_file() { self.picked_path = Some(path.display().to_string()); } }
- 有了文件路径之后,我们就可以通过标准的文件库进行读写了
serde_json
-
json
序列化与反序列化库 -
在之前的文章中我们已经初步接触了
serde
相关知识,这里我们来看看其他内容 -
在我们获取到文件路径后,我们就可以读取json文件了,同时,对于比较大的文件,
serde_json
也提供了from_reader
的方法:use serde::Deserialize; use std::error::Error; use std::fs::File; use std::io::BufReader; use std::path::Path; #[derive(Deserialize, Debug)] struct User { fingerprint: String, location: String, } fn read_user_from_file<P: AsRef<Path>>(path: P) -> Result<User, Box<dyn Error>> { // 使用只读方式读取文件 并使用buffer存储 let file = File::open(path)?; let reader = BufReader::new(file); // 反序列化json数据 let u = serde_json::from_reader(reader)?; // 返回 Ok(u) } fn main() { let u = read_user_from_file("test.json").unwrap(); println!("{:#?}", u); }
-
在我们的例子中,首先定义下结构体:
#[derive(serde::Deserialize, serde::Serialize)] pub struct WorkSpace { pub name: String, pub path: String, pub description: String, pub data: Project, } #[derive(serde::Deserialize, serde::Serialize)] pub struct Project { version: String, scope: String, selected_tree: String, }
-
然后是初始化代码:
impl WorkSpace { pub fn new(path: String) -> Self { Self::from_file(path).unwrap() } fn from_file<P: AsRef<Path>>(path: P) -> Result<WorkSpace, Box<dyn Error>> { // 使用只读方式读取文件 并使用buffer存储 let file = File::open(path)?; let reader = BufReader::new(file); let u = serde_json::from_reader(reader)?; Ok(u) } }
-
我们的json数据如下:
{ "name": "test", "path": "C:\\Users\\b3.txt", "description": null, "data": { "version": "0.0.1", "scope": "project", "selectedTree": "045b5abc-aef7-4909-8d16-5797ebb270e9", } }
-
运行我们的代码,选择json文件,发现报错了:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: null, expected a string", line: xxx, column: 17)', src\project.rs:18:32
这是因为对于
WorkSpace.description
,我们定义的String
类型,但是我们的json数据中却是null
,匹配不上,要解决这个问题,我们可以这样:#[derive(serde::Deserialize, serde::Serialize)] pub struct WorkSpace { pub name: String, pub path: String, pub description: serde_json::Value, pub data: Project, }
将
description
修改为枚举Value
pub enum Value { Null, Bool(bool), Number(Number), String(String), Array(Vec<Value>), Object(Map<String, Value>), }
-
再次运行代码,发现又报错了:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `selected_tree`", line: 245515, column: 2)', src\project.rs:18:32
这是因为
Project.selected_tree
的默认反序列化名称为selected_tree
,而在我们的json
数据中为selectedTree
,这时我们可以这样处理:#[derive(serde::Deserialize, serde::Serialize)] pub struct Project { version: String, scope: String, #[serde(rename(serialize = "selectedTree", deserialize = "selectedTree"))] selected_tree: String, }
这样就可以指定序列化与反序列化时的名称为
selectedTree
-
然后我们来试试序列化并保存文件,同样可以使用I/O stream
pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), serde_json::Error> { let file = File::options().create_new(true).write(true).open(path).unwrap(); let writer = BufWriter::new(file); serde_json::to_writer_pretty(writer, self) }
参考
- rfd
- serde_json
- serde