Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
ini配置文件
STM32 使用fatfs文件系统读取ini格式参数配置文件
发布于 2025-02-19 13:34:31 浏览:57
订阅该版
先上代码 ```c /** * Copyright (c) 2016 rxi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include
#include
#include
#include
#include "ini.h" struct ini_t { char *data; // 原始数据 char *end; // 数据末尾 char *modified_data; // 修改后的数据 size_t modified_size; // 修改后数据的大小 }; /* Case insensitive string compare 不区分大小写的字符串比较 */ static int strcmpci(const char *a, const char *b) { for (;;) { int d = tolower(*a) - tolower(*b); if (d != 0 || !*a) { return d; } a++, b++; } } /* Returns the next string in the split data 返回拆分数据中的下一个字符串 */ static char* next(ini_t *ini, char *p) { p += strlen(p); while (p < ini->end && *p == '\0') { p++; } return p; } static void trim_back(ini_t *ini, char *p) { while (p >= ini->data && (*p == ' ' || *p == '\t' || *p == '\r')) { *p-- = '\0'; } } static char* discard_line(ini_t *ini, char *p) { while (p < ini->end && *p != '\n') { *p++ = '\0'; } return p; } // 动态扩展 modified_data 的大小 static void expand_modified_data(ini_t *ini, size_t additional_size) { size_t new_size = ini->modified_size + additional_size + 1; // +1 用于空字符 ini->modified_data = realloc(ini->modified_data, new_size); if (!ini->modified_data) { fprintf(stderr, "Failed to allocate memory for modified data\n"); exit(1); } ini->modified_size = new_size; } static char *unescape_quoted_value(ini_t *ini, char *p) { /* Use `q` as write-head and `p` as read-head, `p` is always ahead of `q` * as escape sequences are always larger than their resultant data * 使用`q`作为写头,`p`作为读头,`p `总是在`q之前` 因为逃逸序列总是大于其结果数据 */ char *q = p; p++; while (p < ini->end && *p != '"' && *p != '\r' && *p != '\n') { if (*p == '\\') { /* Handle escaped char */ p++; switch (*p) { default : *q = *p; break; case 'r' : *q = '\r'; break; case 'n' : *q = '\n'; break; case 't' : *q = '\t'; break; case '\r' : case '\n' : case '\0' : goto end; } } else { /* Handle normal char处理普通字符 */ *q = *p; } q++, p++; } end: return q; } /* Splits data in place into strings containing section-headers, keys and * values using one or more '\0' as a delimiter. Unescapes quoted values * 将数据就地拆分为包含节标题、键和值 *使用一个或多个“\0”作为分隔符的值。引用值不一致 */ static void split_data(ini_t *ini) { char *value_start, *line_start; char *p = ini->data; while (p < ini->end) { switch (*p) { case '\r': case '\n': case '\t': case ' ': *p = '\0'; /* Fall through 为空*/ case '\0': p++; break; case '[': p += strcspn(p, "]\n"); *p = '\0'; break; case ';': p = discard_line(ini, p); break; default: line_start = p; p += strcspn(p, "=\n"); /* Is line missing a '='? 是否有等号 */ if (*p != '=') { p = discard_line(ini, line_start); break; } trim_back(ini, p - 1); /* Replace '=' and whitespace after it with '\0'将“=”及其后面的空格替换为 '\0' */ do { *p++ = '\0'; } while (*p == ' ' || *p == '\r' || *p == '\t'); /* Is a value after '=' missing?值是否丢失 */ if (*p == '\n' || *p == '\0') { p = discard_line(ini, line_start); break; } if (*p == '"') { /* Handle quoted string value */ value_start = p; p = unescape_quoted_value(ini, p); /* Was the string empty? */ if (p == value_start) { p = discard_line(ini, line_start); break; } /* Discard the rest of the line after the string value */ p = discard_line(ini, p); } else { /* Handle normal value */ p += strcspn(p, "\n"); trim_back(ini, p - 1); } break; } } } ini_t* ini_load(const char *filename) { ini_t *ini = NULL; FILE *fp = NULL; int n, sz; /* Init ini struct */ ini = malloc(sizeof(*ini)); if (!ini) { goto fail; } memset(ini, 0, sizeof(*ini)); /* Open file */ fp = fopen(filename, "rb"); if (!fp) { goto fail; } /* Get file size */ fseek(fp, 0, SEEK_END); sz = ftell(fp); rewind(fp); /* Load file content into memory, null terminate, init end var Load file content into memory, null terminate, init end var */ ini->data = malloc(sz + 1); ini->data[sz] = '\0'; ini->end = ini->data + sz; n = fread(ini->data, 1, sz, fp); if (n != sz) { goto fail; } /* Prepare data */ split_data(ini); /* Initialize modified data */ ini->modified_data = NULL; ini->modified_size = 0; /* Clean up and return */ fclose(fp); return ini; fail: if (fp) fclose(fp); if (ini) ini_free(ini); return NULL; } void ini_free(ini_t *ini) { free(ini->data); if (ini->modified_data) { free(ini->modified_data); } free(ini); } const char* ini_get(ini_t *ini, const char *section, const char *key) { char *current_section = ""; char *val; char *p = ini->data; if (*p == '\0') { p = next(ini, p); } while (p < ini->end) { if (*p == '[') { /* Handle section */ current_section = p + 1; } else { /* Handle key */ val = next(ini, p); if (!section || !strcmpci(section, current_section)) { if (!strcmpci(p, key)) { return val; } } p = val; } p = next(ini, p); } return NULL; } int ini_sget(ini_t *ini, const char *section, const char *key,const char *scanfmt, void *dst) { const char *val = ini_get(ini, section, key); if (!val) { return 0; } if (scanfmt) { sscanf(val, scanfmt, dst); } else { *((const char**) dst) = val; } return 1; } // 添加或修改键值对 void ini_set(ini_t *ini, const char *section, const char *key, const char *value) { // 检查是否已经存在该键值对 const char *old_value = ini_get(ini, section, key); if (old_value) { // 如果存在,则修改值 // 这里需要找到旧值的位置并替换为新值 // 由于原始数据是只读的,我们将在 modified_data 中存储修改后的数据 // 这是一个简化的实现,实际可能需要更复杂的逻辑 char *p = ini->modified_data; while (p < ini->modified_data + ini->modified_size) { if (strcmp(p, key) == 0) { // 找到键,替换值 p += strlen(p) + 1; // 跳过键 strcpy(p, value); // 替换值 break; } p += strlen(p) + 1; // 跳过键 p += strlen(p) + 1; // 跳过值 } } else { // 如果不存在,则添加新的键值对 // 将 section、key 和 value 添加到 modified_data 中 size_t section_len = strlen(section); size_t key_len = strlen(key); size_t value_len = strlen(value); size_t total_len = section_len + key_len + value_len + 5; // 包括 []、= 和两个空字符 // 扩展 modified_data 的大小 expand_modified_data(ini, total_len); // 将 section、key 和 value 添加到 modified_data 中 char *p = ini->modified_data + ini->modified_size - total_len; sprintf(p, "[%s]\n%s=%s\n", section, key, value); ini->modified_size += total_len; } } // 删除键值对 void ini_remove(ini_t *ini, const char *section, const char *key) { // 实现删除逻辑 } //实现文件保存函数 int ini_save(ini_t *ini, const char *filename) { FILE *fp = fopen(filename, "w"); if (!fp) { return -1; // 打开文件失败 } // 将修改后的数据写入文件 if (ini->modified_data) { fwrite(ini->modified_data, 1, ini->modified_size, fp); } else { // 如果没有修改,则写入原始数据 fwrite(ini->data, 1, ini->end - ini->data, fp); } fclose(fp); return 0; // 保存成功 } ``` ```c /** * Copyright (c) 2016 rxi * * This library is free software; you can redistribute it and/or modify it * under the terms of the MIT license. See `ini.c` for details. */ #ifndef INI_H #define INI_H #define INI_VERSION "0.1.1" typedef struct ini_t ini_t; ini_t* ini_load(const char *filename); void ini_free(ini_t *ini); const char* ini_get(ini_t *ini, const char *section, const char *key); int ini_sget(ini_t *ini, const char *section, const char *key, const char *scanfmt, void *dst); #endif ``` 测试程序 ```c void read_write_sample(void) { int fd; fd = open("/config.ini", O_WRONLY | O_CREAT);//创建文件 close(fd); ini_t *ini = ini_load("/config.ini"); if (!ini) { printf("Failed to load INI file\n"); return 1; } // 添加或修改键值对 ini_set(ini, "network", "ip", "192.168.1.101"); ini_set(ini, "network", "port", "8081"); // 保存修改后的 INI 文件 if (ini_save(ini, "/config_modified.ini") != 0) { printf("Failed to save INI file\n"); } else { printf("INI file saved successfully\n"); } // 获取值 const char *ip = ini_get(ini, "network", "ip"); if (ip) { printf("IP: %s\n", ip); } int port; if (ini_sget(ini, "network", "port", "%d", &port)) { printf("Port: %d\n", port); } // 释放资源 ini_free(ini); } ``` 执行ini_t *ini = ini_load("/config.ini")内存溢出。
查看更多
1
个回答
默认排序
按发布时间排序
YZRD
1天前
这家伙很懒,什么也没写!
可以使用 minIni 软件包 ,可参考[stm32单片机 minIni 软件包的使用](https://embedded-rd.blog.csdn.net/article/details/145458269)
撰写答案
登录
注册新账号
关注者
0
被浏览
57
关于作者
Jikun
这家伙很懒,什么也没写!
提问
4
回答
2
被采纳
1
关注TA
发私信
相关问题
1
minIni组件的使用问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
ART-Pi2移植CMSIS-DAP(基于CherryUSB协议栈)
2
RT-thred的stm32h723对应bsp包CubeMX添加其他外设报错
3
RT-Thread中的time溢出问题,时间戳溢出,解决方法
4
ART-PI使用env驱动ETH网卡,pc和板子可以ping通
5
SystemView线程名字不显示
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
9
个答案
2
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
2
篇文章
5
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
lizimu
1
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部