Read and Parse JSON With Rust

主要讲讲 Rust 是如何处理 JSON 格式 / 文件的。

我的需求主要如下：

从一个远程地址下载 JSON 文件，保存到本地

读取这个 JSON 文件

对这个 JSON 文件内容进行搜索匹配

返回搜索结果

本文章的内容主要是集中讲讲第 2 步的内容。
首先需要解析 JSON 格式如下：

Copy
{
"0100000011D90000": {
"bannerUrl": "https://img.../37fdb...f83a.jpg",
"category": [
"Adventure",
"RPG"
],
"description": "Welcome to the Sinnoh region! ",
"developer": null,
"id": "0100000011D90000",
"isDemo": false,
"language": "en",
"name": "Pok\u00e9mon\u2122 Brilliant Diamond",
"nsuId": 70010000039950,
"numberOfPlayers": 1,
"publisher": "Nintendo",
"rank": 30712,
"ratingContent": [
"Mild Cartoon Violence",
"Users Interact",
"In-Game Purchases"
],
"size": 7334789120,
"version": 0
},
...
}

主要会使用到 serde 和 serde_json 这两个库。

先在 Cargo.toml 的 dependencies 中分别引入

Copy
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

建立数据模型 - struct

为了能够使 rust 识别数据结构，需要先创建 struct Game 的数据模型来模仿 JSON 的响应。

rust 使用 struct 来描述数据模型，这里我们派生了 serde 的 Serialize / Deserialize（允许系列化和反序列化） ，需要在头部使用关键词引入 use serde::{ Deserialize, Serialize }

代码如下：

Copy
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Game {
pub banner_url: Option<JsonValue>,
pub category: Option<Vec<JsonValue>>,
pub description: Option<JsonValue>,
pub developer: Option<JsonValue>,
pub id: Option<JsonValue>,
pub is_demo: Option<JsonValue>,
pub language: Option<JsonValue>,
pub name: Option<JsonValue>,
pub nsu_id: Option<usize>,
pub number_of_players: Option<usize>,
pub publisher: Option<JsonValue>,
pub rank: Option<JsonValue>,
pub rating_content: Option<Vec<JsonValue>>,
pub size: Option<JsonValue>,
pub version: Option<JsonValue>,
}

PS: 在 Game 结构体中原始 JSON banner_url 中 bannerUrl 的命名约定会有细微差别，前一个命名为驼峰式 (Camel-Case)，第二个命名为蛇形 (snake_case)，rust 默认更喜欢蛇形命名 (snake_case)。
所以，需要派生了 #[serde(rename_all = "camelCase")]，这里描述了结构体命名的特征，需要重命名 camelCase 中的所有内容。

读取文件

这是一个简单的读取文章的示例

Copy
use std::fs::File;

fn main() {
// 读取 demo.json 文件，并输入文件大小
let demo_file_path = Path::new("appdata/demo.json");
let file = File::open(demo_file_path)?;
// get file metadata
let metadata = file.metadata()?;
println!("The File Size is: {:?} Bytes", metadata.len());
}

要读取文件，请使用 std::fs::File 模块并使用随文件路径传递的 Open 方法。

解析数据

Copy
let content: HashMap<String, Game> = match serde_json::from_reader(&file) {
Ok(content) => {
println!("file loaed success");
content
},
Err(e) => {
println!("file loaed error: {}", e);
Err(e)?
}
};

这里我们使用 serde_json 中的 from_reader 方法读取文件数据并将其解析为 Game 结构体的格式。如果 JSON 的结构有错误，程序将退出，并出现 Err(e) 部分中提到的错误。

顺便提一下，如果我们想读取 HashMap 的值，可以通过 get 方法，例如：

Copy
println!("{:?}", content.unwrap().get("0100000000010000").unwrap().name);

感谢阅读。

本篇文章的源码可以在这里查看 read-and-parse-json-with-rust

--EOF--