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)
相关推荐
Q_Q51100828515 分钟前
python的驾校培训预约管理系统
开发语言·python·django·flask·node.js·php
Tapdata21 分钟前
什么是 Operational Data Hub?它因何而生,又为何能够在当下成为技术共识?
数据库
这里有鱼汤29 分钟前
普通人做量化,数据库该怎么选?
数据库·后端
Dxy123931021637 分钟前
Python正则表达式使用指南:从基础到实战
开发语言·python·正则表达式
YLCHUP1 小时前
题解:P4447 [AHOI2018初中组] 分组
开发语言·数据结构·c++·经验分享·算法·贪心算法·抽象代数
R-G-B1 小时前
【05】大恒相机SDK C#开发 —— Winform中采集图像并显示
开发语言·c#·大恒相机sdk·winform中采集图像·winform中采集图像并显示
BOOM朝朝朝1 小时前
Mongo索引
数据库·后端
三小尛2 小时前
C++友元
开发语言·c++·算法
小小洋洋2 小时前
笔记:C语言中指向指针的指针作用
c语言·开发语言·笔记
许野平2 小时前
Rust 同步方式访问 REST API 的完整指南
java·网络·rust·restful