Rust:如何访问 *.ini 配置文件?

在 Rust 中读写 INI 文件,推荐使用成熟的 configparserini 库。下面提供两种实现方案(基础和高阶),包含完整代码示例:


方案一:使用 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)
相关推荐
人工干智能3 小时前
科普:Python 中,字典的“动态创建键”特性
开发语言·python
初听于你4 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
长路归期无望6 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
恒悦sunsite6 小时前
Ubuntu之apt安装ClickHouse数据库
数据库·clickhouse·ubuntu·列式存储·8123
是大强6 小时前
stm32摇杆adc数据分析
开发语言
奥尔特星云大使7 小时前
MySQL 慢查询日志slow query log
android·数据库·mysql·adb·慢日志·slow query log
来自宇宙的曹先生7 小时前
MySQL 存储引擎 API
数据库·mysql
间彧7 小时前
MySQL Performance Schema详解与实战应用
数据库
间彧7 小时前
MySQL Exporter采集的关键指标有哪些,如何解读这些指标?
数据库
weixin_446260857 小时前
Django - 让开发变得简单高效的Web框架
前端·数据库·django