配置文件
常见的配置文件有很多:JSON, Ini, XML, TOML, YAML ...
目标:
- JSON/YAML/TOML
- Ini
- XML
Rust中序列化用的最多的是 serde
, 依赖它,有很多出色的第三方库可以使用。
其中,serde
本身支持JSON/YAML/TOML/JSON5...多种,这里使用serde_json
.
XML需要第三方库quick-xml
,他通过支持serde
也支持了结构体序列化,配合十分完美.
INI比较特别,这里有一个比较强大的库,支持带注释的ini, configparser
.
依赖文件:
toml
[dependencies]
configparser = "*" # ini支持
serde = { version = "*", features = ["derive"] } # 后续的库的基础
serde_json = "*" # JSON支持
quick-xml = { version = "*",features=["serde","serialize"] } # xml 支持
Code
rust
use configparser::ini::Ini;
use serde_json::{json, Value};
use serde::{Deserialize, Serialize};
use quick_xml;
fn main() {
println!("\r\n1. Ini config");
ini_call();
println!("\r\n2. Json config");
// serde库 支持 json, toml, yaml ... 多种格式,方法也类似
json_call();
println!("\r\n3. XML config");
// 支持 xml encoding 设定
xml_call();
}
fn ini_call() {
let ini_str = r#"default_s1 = 123 ; default section
config s2 : abc,xyz # : also can be accept
# comments
[ app ]
port # default value is also ok
ip = "192.168.1.2"
"#;
let mut conf = Ini::new();
// 解析 ini 内容
if let Ok(cfg) = conf.read(ini_str.to_string()) {
for (k, v) in cfg {
println!("ini section: {} = {:?}", k, v);
}
println!("{:?}, {:?}", conf.getint("default", "default_s1"), conf.get("app", "ip"));
// 修改 ini
conf.set("app", "test", Some("t_val".to_string()));
// output ini
println!("\r\nini output:\r\n{}", conf.writes());
}
}
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u8,
phones: Vec<String>,
}
fn json_call() {
let s1 = r#"
{
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
}"#;
// 解析 json
// map 方式访问,支持数组
if let Ok(mut v) = serde_json::from_str::<Value>(s1) {
println!("{:?} {}", v.get("name"), v["phones"][0]);
// 修改 Json
v["test"]=serde_json::value::Value::String("xxxx".to_string());
println!("value change: {}", v.to_string());
}
// 结构体映射
if let Ok(mut p) = serde_json::from_str::<Person>(s1) {
println!("{:?}", p);
// 修改 Json
p.phones.push("1008611".to_string());
println!("after: {}", serde_json::to_string_pretty(&p).unwrap());
}
// macro json Value
let v1 = json!({
"name": "zhangsan",
"age": 33,
"phones": ["1", "2"]
});
println!("value macro: {}", v1.to_string());
}
#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default)]
struct Translation {
#[serde(rename = "@Tag")] // @属性
tag: String,
#[serde(rename = "@Language")]
lang: String,
#[serde(rename = "$text")] // $内容
text: String,
}
#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default)]
struct DefaultSettings {
#[serde(rename = "@Language")]
language: String,
#[serde(rename = "@Greeting")]
greeting: String,
}
#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default, rename_all = "PascalCase")]
struct Config {
#[serde(rename = "DefaultSettings")]
settings: DefaultSettings,
localization: Localization,
}
#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Localization {
translation: Vec<Translation>,
}
const XML: &str = r#"
<?xml version="1.0" encoding="utf-8"?>
<Config>
<DefaultSettings Language="es" Greeting="HELLO"/>
<Localization>
<Translation Tag="HELLO" Language="ja">
こんにちは
</Translation>
<Translation Tag="BYE" Language="ja">
さようなら
</Translation>
<Translation Tag="HELLO" Language="es">
Hola
</Translation>
<Translation Tag="BYE" Language="es">
Adiós
</Translation>
</Localization>
</Config>
"#;
const XML2: &str = r#"
<Translation Tag="HELLO" Language="ja">
こんにちは
</Translation>
"#;
fn xml_call(){
// 简单解析XML
if let Ok(t2) = quick_xml::de::from_str::<Translation>(XML2){
println!("xml2 struct:\r\n\t {:?}", t2);
}
// 复杂的解析XML
if let Ok(mut t) = quick_xml::de::from_str::<Config>(XML){
println!("xml settings: \r\n\t{:?}", t.settings);
println!("xml localization: \r\n\t{:?}", t.localization);
// 修改XML
t.settings.greeting = "good good study".to_string();
// out
println!("format output:\r\n\t{}",quick_xml::se::to_string(&t).unwrap());
}
}
输出
js
1. Ini config
ini section: app = {"ip": Some("\"192.168.1.2\""), "port": None}
ini section: default = {"default_s1": Some("123"), "config s2": Some("abc,xyz")}
Ok(Some(123)), Some("\"192.168.1.2\"")
ini output:
default_s1=123
config s2=abc,xyz
[app]
ip="192.168.1.2"
test=t_val
port
2. Json config
Some(String("John Doe")) "+44 1234567"
value change: {"age":43,"name":"John Doe","phones":["+44 1234567","+44 2345678"],"test":"xxxx"}
Person { name: "John Doe", age: 43, phones: ["+44 1234567", "+44 2345678"] }
after: {
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678",
"1008611"
]
}
value macro: {"age":33,"name":"zhangsan","phones":["1","2"]}
3. XML config
xml2 struct:
Translation { tag: "HELLO", lang: "ja", text: "こんにちは" }
xml settings:
DefaultSettings { language: "es", greeting: "HELLO" }
xml localization:
Localization { translation: [Translation { tag: "HELLO", lang: "ja", text: "こんにちは" }, Translation { tag: "BYE", lang: "ja", text: "さようなら" }, Translation { tag: "HELLO", lang: "es", text: "Hola" }, Translation { tag: "BYE", lang: "es", text: "Adiós" }] }
format output:
<Config><DefaultSettings Language="es" Greeting="good good study"/><Localization><Translation Tag="HELLO" Language="ja">こんにちは</Translation><Translation Tag="BYE" Language="ja">さようなら</Translation><Translation Tag="HELLO" Language="es">Hola</Translation><Translation Tag="BYE" Language="es">Adiós</Translation></Localization></Config>