在 Rust 中读写 INI 文件,推荐使用成熟的 configparser
或 ini
库。下面提供两种实现方案(基础和高阶),包含完整代码示例:
方案一:使用 configparser
(功能更强大)
1. 添加依赖
toml
[dependencies]
configparser = "3.0.2"
anyhow = "1.0" # 可选,用于错误处理
2. 读写 INI 文件完整示例
rust
use anyhow::Result;
use configparser::ini::Ini;
fn main() -> Result<()> {
// ===== 写入 INI 文件 =====
let mut config = Ini::new();
// 添加全局值
config.set("", "debug", Some("true"));
config.set("", "timeout", Some("30"));
// 添加带节的配置
config.set("server", "host", Some("localhost"));
config.set("server", "port", Some("8080"));
// 添加另一个节
config.set("user", "name", Some("Alice"));
config.set("user", "active", Some("yes"));
// 写入文件(支持注释)
config.write_to_path("config.ini")?;
// ===== 读取 INI 文件 =====
let mut config_read = Ini::new();
config_read.load("config.ini")?;
// 读取全局值
let debug = config_read.getbool("", "debug")?.unwrap();
println!("Debug enabled: {}", debug);
// 读取带节的值
let port: i32 = config_read.get("server", "port")?
.parse()
.unwrap_or(8080);
println!("Server port: {}", port);
// 读取整段
if let Some(user_section) = config_read.sections().get("user") {
println!("User name: {}", user_section["name"]);
}
// 更新并保存
config_read.set("user", "active", Some("no"));
config_read.write_to_path("config.ini")?;
Ok(())
}
3. 高级特性
rust
// 1. 自定义解析类型
let timeout: u64 = config_read.getuint("", "timeout")?.unwrap();
// 2. 添加注释
config.set_comment("", "debug", vec!["; Global debug flag"]);
config.set_section_comment("user", vec!["", "# User settings", ""]);
// 3. 多行值处理
config.set("multiline", "description", Some("这是\\n多行\\n值"));
let desc = config.get("multiline", "description").unwrap();
// => "这是\n多行\n值"
// 4. 错误处理强化
match config.get("invalid_section", "key") {
Ok(Some(val)) => println!("Value: {}", val),
Ok(None) => println!("Key not found"),
Err(e) => eprintln!("Error: {}", e),
}
方案二:使用 ini
(轻量级)
1. 添加依赖
toml
[dependencies]
ini = "3.0.1"
2. 基础读写操作
rust
use ini::Ini;
use anyhow::Result;
fn main() -> Result<()> {
// ===== 创建新INI文件 =====
let mut conf = Ini::new();
// 添加全局属性
conf.with_general_section()
.set("debug", "true")
.set("timeout", "30");
// 添加节
conf.with_section(Some("server"))
.set("host", "localhost")
.set("port", "8080");
// 添加带注释的节
conf.with_section(Some("user"))
.set("name", "Alice")
.set("active", "yes");
// 写入文件
conf.write_to_file("config.ini")?;
// ===== 读取文件 =====
let conf_read = Ini::load_from_file("config.ini")?;
// 读取全局属性
if let Some(debug_val) = conf_read.general_section().get("debug") {
println!("Debug: {}", debug_val);
}
// 读取具体节
if let Some(user) = conf_read.section(Some("user")) {
let name = user.get("name").unwrap_or_default();
println!("User name: {}", name);
}
// 遍历所有节
for (sec, props) in &conf_read {
println!("[{sec}]");
for (key, value) in props.iter() {
println!("{key} = {value}");
}
}
Ok(())
}
3. 自定义配置
rust
// 1. 自定义分隔符(默认为 =)
let mut conf = Ini::new_custom();
conf.section_mut(Some("section"))
.insert_with_separator("key", "value", ":");
// => key: value
// 2. 保留注释
let conf = Ini::load_from_file("config.ini")?;
println!("原始注释: {:#?}", conf);
// 3. 复杂数据类型
conf.with_section(Some("database"))
.set("port", 5432.to_string())
.set("active", true.to_string());
功能对比表
特性 | configparser |
ini |
---|---|---|
类型转换 | ✅ (getint, getbool 等) | ❌ |
注释处理 | ✅ (完整支持) | ✅ (部分支持) |
多行值 | ✅ | ✅ |
默认值支持 | ✅ | ❌ |
文件自动重载 | ❌ | ❌ |
错误处理 | ⭐⭐⭐⭐ | ⭐⭐ |
性能 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
文件大小限制 | 无 | 无 |
错误处理最佳实践
rust
use configparser::ini::IniError;
fn load_config() -> Result<(), IniError> {
let mut config = Ini::new();
// 优雅处理缺失值
let host = config.get("server", "host")
.ok_or(IniError::MissingSectionOrKey("server.host".into()))?;
// 强制类型转换
let port: u16 = config.get("server", "port")
.and_then(|s| s.parse().ok())
.ok_or(IniError::ValueError("Invalid port format".into()))?;
println!("Connecting to {host}:{port}");
Ok(())
}
INI 文件标准示例
ini
; 全局配置
debug = true
timeout = 30
[server]
# 服务器地址
host = 127.0.0.1
port = 8080 ; HTTP 端口
[database]
user = dbadmin
password = "secret!@#$"
替代方案:手动解析(不推荐)
对于简单需求可自行处理:
rust
use std::fs;
use anyhow::Context;
fn parse_ini(path: &str) -> anyhow::Result<()> {
let contents = fs::read_to_string(path)?;
let mut current_section = "default";
for line in contents.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with(';') || line.starts_with('#') {
continue;
}
if let Some(section) = line.strip_prefix('[').and_then(|s| s.strip_suffix(']')) {
current_section = section;
continue;
}
if let Some((key, value)) = line.split_once('=') {
let key = key.trim();
let value = value.trim();
println!("Section: {current_section}, Key: {key}, Value: {value}");
}
}
Ok(())
}
注意:手动解析无法处理复杂情况(如转义字符、多行值等),建议优先使用现成库。
根据需求选择库:
- 需要复杂值类型转换 → 选
configparser
- 只需要基本键值读取 → 选
ini
- 需要集成系统配置 → 考虑
confy
(基于serde
)