C语言实现INI配置文件读取和写入

一.INI文件介绍

INI配置文件是一种简单的文本文件,用于存储配置信息,通常由一个或多个节(section)组成,每个节包含多个键值对(Key-Value)格式。INI文件易于阅读和编辑,广泛应用于多种程序和应用中。

二.基本格式

INI文件由若干个节(section)组成,每个节由方括号包围的标题表示,例如 [SectionName]。每个节可以包含多个键值对,格式为 key=value。注释用分号(;)表示,放在注释之前的行被视为注释。例如:

[network]

host = 127.0.0.1

port = 8081

[database]

user = admin

三.C代码实现

1.编译环境:VS2022

2.代码

#define _CRT_SECURE_NO_WARNINGS  // 禁用安全警告  //防止fopen告警

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#define MAX_LINE_LENGTH 256    //一行字符串最大长度

#define MAX_SECTION_LENGTH 64  //section字符串最大长度

#define MAX_KEY_LENGTH 64      //key字符串最大长度

typedef struct KeyValue {

    char key[MAX_KEY_LENGTH];

    char* value;

    struct KeyValue* next;

} KeyValue;

typedef struct Section {

    char name[MAX_SECTION_LENGTH];

    KeyValue* pairs;

    struct Section* next;

} Section;

typedef struct IniFile {

    Section* sections;

} IniFile;

// 辅助函数:去除字符串首尾空白

char* trim(char* str) {

    while (isspace((unsigned char)*str)) str++;

    if (*str == 0) return str;

    char* end = str + strlen(str) - 1;

    while (end > str && isspace((unsigned char)*end)) end--;

    *(end + 1) = '\0';

    return str;

}

// 加载INI文件

IniFile* ini_load(const char* filename) {

    FILE* file = fopen(filename, "r");

    if (!file) return NULL;

    IniFile* ini = (IniFile*)calloc(1, sizeof(IniFile));

    Section* current_section = NULL;

    char line[MAX_LINE_LENGTH];

    while (fgets(line, sizeof(line), file)) {

        char* trimmed = trim(line);

        // 跳过空行和注释

        if (*trimmed == '\0' || *trimmed == ';' || *trimmed == '#') continue;

        // 处理节

        if (*trimmed == '[') {

            char* end = strchr(trimmed, ']');

            if (end) {

                *end = '\0';

                char* section_name = trim(trimmed + 1);

                Section* section = (Section*)calloc(1, sizeof(Section));

                strncpy(section->name, section_name, sizeof(section->name) - 1);

                // 添加到链表

                if (!ini->sections) {

                    ini->sections = section;

                }

                else {

                    Section* last = ini->sections;

                    while (last->next) last = last->next;

                    last->next = section;

                }

                current_section = section;

            }

            continue;

        }

        // 处理键值对

        if (current_section) {

            char* sep = strchr(trimmed, '=');

            if (sep) {

                *sep = '\0';

                char* key = trim(trimmed);

                char* value = trim(sep + 1);

                KeyValue* pair = (KeyValue*)calloc(1, sizeof(KeyValue));

                strncpy(pair->key, key, sizeof(pair->key) - 1);

                pair->value = _strdup(value); // VS中使用安全版本

                // 添加到链表

                if (!current_section->pairs) {

                    current_section->pairs = pair;

                }

                else {

                    KeyValue* last = current_section->pairs;

                    while (last->next) last = last->next;

                    last->next = pair;

                }

            }

        }

    }

    fclose(file);

    return ini;

}

// 获取值

const char* ini_get(IniFile* ini, const char* section, const char* key) {

    Section* s = ini->sections;

    while (s) {

        if (strcmp(s->name, section) == 0) {

            KeyValue* p = s->pairs;

            while (p) {

                if (strcmp(p->key, key) == 0) {

                    return p->value;

                }

                p = p->next;

            }

            return NULL;

        }

        s = s->next;

    }

    return NULL;

}

// 设置值

void ini_set(IniFile* ini, const char* section, const char* key, const char* value) {

    Section* s = ini->sections;

    Section* prev_section = NULL;

    // 查找或创建section

    while (s) {

        if (strcmp(s->name, section) == 0) break;

        prev_section = s;

        s = s->next;

    }

    if (!s) {

        s = (Section*)calloc(1, sizeof(Section));

        strncpy(s->name, section, sizeof(s->name) - 1);

        if (prev_section) {

            prev_section->next = s;

        }

        else {

            ini->sections = s;

        }

    }

    // 查找或创建key

    KeyValue* p = s->pairs;

    KeyValue* prev_pair = NULL;

    while (p) {

        if (strcmp(p->key, key) == 0) {

            free(p->value);

            p->value = _strdup(value); // VS中使用安全版本

            return;

        }

        prev_pair = p;

        p = p->next;

    }

    KeyValue* new_pair = (KeyValue*)calloc(1, sizeof(KeyValue));

    strncpy(new_pair->key, key, sizeof(new_pair->key) - 1);

    new_pair->value = _strdup(value); // VS中使用安全版本

    if (prev_pair) {

        prev_pair->next = new_pair;

    }

    else {

        s->pairs = new_pair;

    }

}

// 保存INI文件

int ini_save(IniFile* ini, const char* filename) {

    FILE* file = fopen(filename, "w");

    if (!file) return -1;

    Section* s = ini->sections;

    while (s) {

        fprintf(file, "[%s]\n", s->name);

        KeyValue* p = s->pairs;

        while (p) {

            fprintf(file, "%s = %s\n", p->key, p->value);

            p = p->next;

        }

        fprintf(file, "\n");

        s = s->next;

    }

    fclose(file);

    return 0;

}

// 释放内存

void ini_free(IniFile* ini) {

    Section* s = ini->sections;

    while (s) {

        Section* next_s = s->next;

        KeyValue* p = s->pairs;

        while (p) {

            KeyValue* next_p = p->next;

            free(p->value);

            free(p);

            p = next_p;

        }

        free(s);

        s = next_s;

    }

    free(ini);

}

// 示例用法

int main()

{

    #define FILE_NAME "d:/30.VS/12.c配置文件/config.ini" 

    // 写入测试

    IniFile* ini = ini_load(FILE_NAME);

    if (!ini) ini = (IniFile*)calloc(1, sizeof(IniFile));

    ini_set(ini, "network", "host", "127.0.0.1");

    ini_set(ini, "network", "port", "8080");

    ini_set(ini, "database", "user", "admin");

    ini_set(ini, "network", "port", "8081");  //修改值

    ini_save(ini, FILE_NAME);

    // 读取测试

    IniFile* read_ini = ini_load(FILE_NAME);

    const char* host = ini_get(read_ini, "network", "host");

    printf("Host: %s\n", host);

    ini_free(ini);

    ini_free(read_ini);

    system("pause"); // 防止控制台窗口关闭

    return 0;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/80188.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 3 打开 el-dialog 时使 el-input 获取焦点

运行代码&#xff1a;https://andi.cn/page/622178.html 效果&#xff1a;

【程序员AI入门:模型】19.开源模型工程化全攻略:从选型部署到高效集成,LangChain与One-API双剑合璧

一、模型选型与验证&#xff1a;精准匹配业务需求 &#xff08;一&#xff09;多维度评估体系 通过量化指标权重实现科学选型&#xff0c;示例代码计算模型综合得分&#xff1a; # 评估指标权重与模型得分 requirements {"accuracy": 0.4, "latency": …

卡顿检测与 Choreographer 原理

一、卡顿检测的原理 卡顿的本质是主线程&#xff08;UI 线程&#xff09;未能及时完成某帧的渲染任务&#xff08;超过 16.6ms&#xff0c;以 60Hz 屏幕为例&#xff09;&#xff0c;导致丢帧&#xff08;Frame Drop&#xff09;。检测卡顿的核心思路是监控主线程任务的执行时…

物联网僵尸网络防御:从设备认证到流量染色

一、IoT设备的安全困境 典型物联网设备存在硬编码密钥问题&#xff1a; // 固件中的危险代码示例 const char* DEFAULT_KEY "A1B2-C3D4-E5F6"; // 厂商预设密钥 void connect_server() {authenticate(DEFAULT_KEY); // 密钥从未更新 }此类漏洞导致某智能家居平台…

二叉树子树判断:从递归到迭代的全方位解析

一、题目解析 题目描述 给定两棵二叉树root和subRoot&#xff0c;判断root中是否存在一棵子树&#xff0c;其结构和节点值与subRoot完全相同。 示例说明 示例1&#xff1a; root [3,4,5,1,2]&#xff0c;subRoot [4,1,2] 返回true&#xff0c;因为root的左子树与subRoot完…

Springboot 异步场景 使用注解 @Async 及 自定义线程池分模块使用

目录 前言一、Springboot项目如何开启异步&#xff1f;二、存在的问题三、自定义线程池四、自定义线程池使用五、阻塞队列和拒绝策略 前言 当开发中遇到不影响主流程任务时&#xff0c;使用异步去处理。 如有以下场景&#xff1a; 1、业务需要生成一个季度的数据进行员工排名&…

【GNN笔记】Signed Graph Convolutional Network(12)【未完】

视频链接&#xff1a;《图神经网络》 Signed Graph Convolutional Network 之前介绍的GNN模型主要集中在无符号的网络&#xff08;或仅由正链接组成的图&#xff09;上&#xff0c;符号 图带来的挑战&#xff0c;主要集中在于 否定链接&#xff0c;与正链接相比&#xff0c;它不…

米勒电容补偿的理解

米勒电容补偿是使运放放大器稳定的重要手法&#xff0c;可以使两级运放的两个极点分离&#xff0c;从而可以得到更好的相位裕度。 Miller 电容补偿的本质是增加一条通路流电流&#xff0c;流电流才是miller效应的本质。给定一个相同的输入&#xff0c;Miller 电容吃掉的电流比…

CVE-2017-8046 漏洞深度分析

漏洞概述 CVE-2017-8046 是 Spring Data REST 框架中的一个高危远程代码执行漏洞&#xff0c;影响版本包括 Spring Data REST < 2.5.12、2.6.7、3.0 RC3 及关联的 Spring Boot 和 Spring Data 旧版本。攻击者通过构造包含恶意 SpEL&#xff08;Spring Expression Language&…

qt文本边框设置

// 计算文本的大致尺寸 QFontMetrics fm(textEditor->font()); QRect textRect fm.boundingRect(textItem->toPlainText()); // 设置编辑框大小&#xff0c;增加一些边距 const int margin 10; textEditor->setGeometry( center.x() - textRect.width()/2 - margin,…

Java 与 面向对象编程(OOP)

Java 是典型的纯面向对象编程语言&#xff08;Pure Object-Oriented Language&#xff09;&#xff0c;其设计严格遵循面向对象&#xff08;OOP&#xff09;的核心原则。以下是具体分析&#xff1a; 1. Java 的面向对象核心特性 (1) 一切皆对象 Java 中几乎所有的操作都围绕…

导出导入Excel文件(详解-基于EasyExcel)

前言&#xff1a; 近期由于工作的需要&#xff0c;根据需求需要导出导入Excel模板。于是自学了一下下&#xff0c;在此记录并分享&#xff01;&#xff01; EasyExcel&#xff1a; 首先我要在这里非常感谢阿里的大佬们&#xff01;封装这么好用的Excel相关的API&#xff0c;真…

python版本管理工具-pyenv轻松切换多个Python版本

在使用python环境开发时&#xff0c;相信肯定被使用版本所烦恼&#xff0c;在用第三方库时依赖兼容的python版本不一样&#xff0c;有没有一个能同时安装多个python并能自由切换的工具呢&#xff0c;那就是pyenv&#xff0c;让你可以轻松切换多个Python 版本。 pyenv是什么 p…

Elasticsearch 索引副本数

作者&#xff1a;来自 Elastic Kofi Bartlett 解释如何配置 number_of_replicas、它的影响以及最佳实践。 更多阅读&#xff1a;Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica 想获得 Elastic 认证&#xff1f;查看下一期 Elasticsearc…

AXI4总线协议 ------ AXI_LITE协议

一、AXI 相关知识介绍 https://download.csdn.net/download/mvpkuku/90841873 AXI_LITE 选出部分重点&#xff0c;详细文档见上面链接。 1.AXI4 协议类型 2.握手机制 二、AXI_LITE 协议的实现 1. AXI_LITE 通道及各通道端口功能介绍 2.实现思路及框架 2.1 总体框架 2.2 …

idea运行

各种小kips Linuxidea上传 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目录下&#xff0c;找到对应项目目录&#xff0c;把原来的jar包放在bak文件夹里面 3、杀死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再进行上传新的jar…

FPGA: XILINX Kintex 7系列器件的架构

本文将详细介绍Kintex-7系列FPGA器件的架构。以下内容将涵盖Kintex-7的核心架构特性、主要组成部分以及关键技术&#xff0c;尽量全面且结构化&#xff0c;同时用简洁的语言确保清晰易懂。 Kintex-7系列FPGA架构概述 Kintex-7是Xilinx 7系列FPGA中的中高端产品线&#xff0c;基…

【LLM】大模型落地应用的技术 ——— 推理训练 MOE,AI搜索 RAG,AI Agent MCP

【LLM】大模型落地应用的技术 ——— 推理训练MOE&#xff0c;AI搜索RAG&#xff0c;AI Agent MCP 文章目录 1、推理训练 MOE2、AI搜索 RAG3、AI Agent MCP 1、推理训练 MOE MoE 是模型架构革新&#xff0c;解决了算力瓶颈。原理是多个专家模型联合计算。 推理训练MoE&#xff…

10 web 自动化之 yaml 数据/日志/截图

文章目录 一、yaml 数据获取二、日志获取三、截图 一、yaml 数据获取 需要安装 PyYAML 库 import yaml import os from TestPOM.common import dir_config as Dir import jsonpathclass Data:def __init__(self,keyNone,file_name"test_datas.yaml"):file_path os…

中exec()函数因$imagePath参数导致的命令注入漏洞

exec(zbarimg -q . $imagePath, $barcodeList, $returnVar); 针对PHP中exec()函数因$imagePath参数导致的命令注入漏洞&#xff0c;以下是安全解决方案和最佳实践&#xff1a; 一、漏洞原理分析 直接拼接用户输入$imagePath到系统命令中&#xff0c;攻击者可通过注入特殊字…