当前位置: 首页 > news >正文

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;

}

相关文章:

  • 论文浅尝 | HOLMES:面向大语言模型多跳问答的超关系知识图谱方法(ACL2024)
  • 论信息系统项目的范围管理
  • 大模型笔记-“训练”和“推理”概念
  • 数据库表字段插入bug
  • vhca_id 简介,以及同 pf, vf 的关系
  • 初识SOC:RK3588
  • UML活动图零基础入门:1 分钟掌握核心逻辑(附实战模板)
  • 后端框架(2):Java的反射机制
  • 5G行业专网部署费用详解:投资回报如何最大化?
  • Java 接口中实现异步处理的方法
  • milvus学习笔记
  • 虚拟来电 4.3.0 |集虚拟来电与短信于一体,解锁VIP优雅脱身
  • Android从单体架构迁移到模块化架构。你会如何设计模块划分策略?如何处理模块间的通信和依赖关系
  • 从实模式到保护模式
  • 每日算法刷题Day8 5.15:leetcode滑动窗口4道题,用时1h
  • 使用Python实现简单的人工智能聊天机器人
  • 【基础】Windows开发设置入门6:Scoop开发者完全指南(AI整理)
  • AXI-LITE slave读写时序
  • MySQL 与 FastAPI 交互教程
  • 589. N叉树的前序遍历迭代法:null指针与栈的巧妙配合
  • 淮安市车桥中学党总支书记王习元逝世,终年51岁
  • 昔日千亿房企祥生集团约2.03亿元债权被拍卖,起拍价8000万元
  • 铁路端午假期运输火车票今日开售,12306提升应对超大规模并发访问需求能力
  • 深圳南澳码头工程环评将再次举行听证会,项目与珊瑚最近距离仅80米
  • 国防部:菲方应停止一切侵权挑衅危险举动,否则只会自食苦果
  • 曾犯强奸罪教师出狱后办教培机构?柳州鱼峰区教育局回应