一.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;
}