JoeZhao

跨出界

Hey, I’m JoeZhao, a software engineer, and a gamer.

使用Rust读取和解析JSON

主要講講 Rust 是如何處理 JSON 格式 / 檔案的。

我的需求主要如下:

  1. 從一個遠程地址下載 JSON 檔案,保存到本地
  2. 讀取這個 JSON 檔案
  3. 對這個 JSON 檔案內容進行搜索匹配
  4. 返回搜索結果

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

{
    "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
    },
    ...
}

主要會使用到 serdeserde_json 這兩個庫。

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

[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 }

代碼如下:

#[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 中的所有內容。

讀取檔案#

這是一個簡單的讀取文章的示例

use std::fs::File;

fn main() {
    // 讀取 demo.json 檔案,並輸入檔案大小
    let demo_file_path = Path::new("appdata/demo.json");
    let file = File::open(demo_file_path)?;
    // 獲取檔案元數據
    let metadata = file.metadata()?;
    println!("The File Size is: {:?} Bytes", metadata.len());
}

要讀取檔案,請使用 std::fs::File 模塊並使用隨檔案路徑傳遞的 Open 方法。

解析數據#

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 方法,例如:

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

感謝閱讀。

本篇文章的源碼可以在這裡查看 read-and-parse-json-with-rust

--EOF--

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。