如何解析JSON文件?

104

我在Rust中解析JSON数据的目标到目前为止是这样的:

extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io::copy;
use std::io::stdout;

fn main() {
    let mut file = File::open("text.json").unwrap();
    let mut stdout = stdout();
    let mut str = &copy(&mut file, &mut stdout).unwrap().to_string();
    let data = Json::from_str(str).unwrap();
}

并且text.json

{
    "FirstName": "John",
    "LastName": "Doe",
    "Age": 43,
    "Address": {
        "Street": "Downing Street 10",
        "City": "London",
        "Country": "Great Britain"
    },
    "PhoneNumbers": [
        "+44 1234567",
        "+44 2345678"
    ]
}

我接下来该怎么解析它?我的主要目标是获取像这样的JSON数据,并从中解析一个键,比如Age。


看起来你已经找到了正确的页面来解析它。你有没有看到页面下方的示例,它看起来正是你想要的? - squiguy
@squiguy,是的,我添加了let obj = data.as_object().unwrap();并得到了thread '<main>' panicked at 'called Option::unwrap()on aNone value', C:/bot/slave/stable-dist-rustc-win-32/build/src/libcore\option.rs:362 }An unknown error occurred - Vikaton
6个回答

95

Serde 是首选的 JSON 序列化提供程序。您可以以多种方式从文件中读取 JSON 文本。一旦您将其作为字符串获取,使用serde_json::from_str

fn main() {
    let the_file = r#"{
        "FirstName": "John",
        "LastName": "Doe",
        "Age": 43,
        "Address": {
            "Street": "Downing Street 10",
            "City": "London",
            "Country": "Great Britain"
        },
        "PhoneNumbers": [
            "+44 1234567",
            "+44 2345678"
        ]
    }"#;

    let json: serde_json::Value =
        serde_json::from_str(the_file).expect("JSON was not well-formatted");
}

Cargo.toml:

[dependencies]
serde = { version = "1.0.104", features = ["derive"] }
serde_json = "1.0.48"
你甚至可以使用类似于serde_json::from_reader这样的东西来直接从打开的File中读取。
Serde可用于除JSON以外的其他格式,并且它可以将序列化和反序列化到自定义结构而不是任意集合中:
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Person {
    first_name: String,
    last_name: String,
    age: u8,
    address: Address,
    phone_numbers: Vec<String>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Address {
    street: String,
    city: String,
    country: String,
}

fn main() {
    let the_file = /* ... */;

    let person: Person = serde_json::from_str(the_file).expect("JSON was not well-formatted");
    println!("{:?}", person)
}

请查看Serde网站获取更多详情。


42

得到了Rust社区众多乐于助人的成员的帮助解决:

extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("text.json").unwrap();
    let mut data = String::new();
    file.read_to_string(&mut data).unwrap();

    let json = Json::from_str(&data).unwrap();
    println!("{}", json.find_path(&["Address", "Street"]).unwrap());
}

21
注意,rustc_serialize仓库现在已经被弃用,推荐使用https://github.com/serde-rs/json。 - FrickeFresh

40

serde_json::de::from_reader文档中有一个简短而完整的示例,演示如何从文件中读取JSON。

下面是一个简短的代码片段,用于:

  • 读取一个文件
  • 将其内容解析为JSON
  • 提取想要的键字段

请享用:

let file = fs::File::open("text.json")
    .expect("file should open read only");
let json: serde_json::Value = serde_json::from_reader(file)
    .expect("file should be proper JSON");
let first_name = json.get("FirstName")
    .expect("file should have FirstName key");

已经有一个使用serde_json的答案了。请[编辑]此答案,以更清楚地显示何处不同和有用,值得重复。 - Shepmaster
谢谢,我喜欢这种无需在JSON中键入所有内容的方法。 - undefined

6

我已经点赞了被接受的答案(因为它有帮助),但是我想补充我的答案,使用广泛使用的serde_json crate,由@FrickeFresh提供引用。

假设你的foo.json是这样的:

{
    "name": "Jane",
    "age": 11
}

实现类似于这样:
extern crate serde;
extern crate json_serde;
#[macro_use] extern crate json_derive;
use std::fs::File;
use std::io::Read;

#[derive(Serialize, Deserialize)]
struct Foo {
    name: String,
    age: u32,
}

fn main() {
   let mut file = File::open("foo.json").unwrap();
   let mut buff = String::new();
   file.read_to_string(&mut buff).unwrap();

   let foo: Foo = serde_json::from_str(&buff).unwrap();
   println!("Name: {}", foo.name);
}

1
已经有一个使用serde_json的答案了。请[编辑] 答案,以更清楚地显示何处不同和有用,值得重复。 - Shepmaster
1
与其他答案不同,如何从文件中获取字符串并未描述。这是一个完整的示例,演示如何使用serde从单独的文件(foo.json)读取,并将该字符串read_to_string最终解包。此外,serde_json的链接不起作用,网站上的serde_json :: from_reader()示例也不起作用。 - Zargold
它不起作用。buff的寿命不够长,借用的值也不够长。 - Wiktor Kujawa

6
您可以将此功能提取为实用程序。根据他们的文档,这可能是一个有效的软件片段。
use std::{
    fs::File,
    io::BufReader,
    path::Path,
    error::Error
};

use serde_json::Value;

fn read_payload_from_file<P: AsRef<Path>>(path: P) -> Result<Value, Box<dyn Error>> {
    // Open file in RO mode with buffer
    let file = File::open(path)?;
    let reader = BufReader::new(file);

    // Read the JSON contents of the file
    let u = serde_json::from_reader(reader)?;

    Ok(u)
}

fn main() {
  let payload: Value = 
     read_payload_from_file("./config/payload.json").unwrap();
}

-3
Rust带有一个优雅的native-json crate,它使用Rust声明本地JSON对象,并提供对成员的本地访问。 native-json的示例
use native_json::json;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};

fn main()
{
    let mut json = json!{
        name: "native json",
        style: {
            color: "red",
            size: 12,
            bold: true,
            range: null
        },
        array: [5,4,3,2,1],
        vector: vec![1,2,3,4,5],
        hashmap: HashMap::from([ ("a", 1), ("b", 2), ("c", 3) ]);,
        students: [
            {name: "John", age: 18},
            {name: "Jack", age: 21},
        ],
    };

    // Native access
    json.style.size += 1;
    json.students[0].age += 2;

    // Debug
    println!("{:#?}", t);

    // Stringify
    let text = serde_json::to_string_pretty(&json).unwrap();
    println!("{}", text);
}

本地 JSON 方式

use wsd::json::*;

fn main() {
    // Declare as native JSON object
    let mut john = json!{
        name: "John Doe",
        age: 43,
        phones: [
            "+44 1234567",
            "+44 2345678"
        ]
    };

    // Native access to member
    john.age += 1;

    println!("first phone number: {}", john.phones[0]);

    // Convert to a string of JSON and print it out
    println!("{}", stringify(&john, 4));
}

serde_json 方法

use serde_json::json;

fn main() {
    // The type of `john` is `serde_json::Value`
    let john = json!({
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    });

    println!("first phone number: {}", john["phones"][0]);

    // Convert to a string of JSON and print it out
    println!("{}", john.to_string());
}

不错,但它并没有回答问题。这使您可以将 JSON 粘贴到代码中,但无法解析外部文件。 - Simson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接