INI文件是Windows上独有的一种存储结构,这只是Windows下发明的存储结构,也有很多类似的,比如xml!
就说一下TXT文本
是按行读取,这就是它的格式!
而xml是类似二叉树的带层次结构的存储方式
INI则是以键值的方式将数据对应起来,类似数据库一样!
在Windows上我们可以使用一些自带API实现对INI文件的读取写入,但是在其它系统平台上就不可以了,这里是博主在开发跨平台SDT工具包时,写的一款对INI文件操作的函数
在开始之前我们需要编写一些辅助函数,因为这些存储结构,都是对字符进行处理,我们先读入内存,然后开始字符流处理,这里值得注意的是!
所以需要编写一些CharString处理字符类,这里是从CharString库里copy出来的,这个库是我开源的,你可以在我的博客SDT分类里找到这个库的介绍以及源码!
//获取文本所在行
int GetStrTxTIndx(char* m_str,const char* Str){
if (m_str == NULL || Str == NULL){
return 0;
}
int StrSize = strlen(Str);
if (StrSize <= 0){
return 0;
}
int Str_m_str = strlen(m_str);
int m_str_index = 0;/*二次循环坐标*/
int y = 0;
for (int i = 0; i <= Str_m_str - 1; i++/*加一是因为i从0开始,下方循环是size+1是为了将坐标移动到下个字符*/){
y = 0;
m_str_index = i;
for (int j = 0; j <= StrSize - 1; ++j, ++m_str_index){
if (Str[j] == m_str[m_str_index]){
y += 1;
}
if (y == StrSize){
return i + 1;
}
if (Str[j] != m_str[m_str_index]){
break;
}
}
}
return 0;
}
//获取一行文本
char* GetLineTxT(char* m_str,int LineIndex = 1) {
if (LineIndex == 0){
return 0;
}
if (m_str == NULL) {
return 0;
}
int l = 0;
char *yun = NULL;
int j = 0;
int u = 0;
for (int i = 0; i <= strlen(m_str) + 1/*包含\0*/; ++i) {
if (m_str[i] == '\n') {
++l;
if (l != LineIndex)
u = i + 1;//+1跳过\n 这里递增1后面已经忽略0因为已经不是第一行坐标
}
if (l == LineIndex) {
//判断此行多长用于分配内存
for (j = u;; ++j) {
if (m_str[j] == '\n' || m_str[j] == '\0') {
int size = 0;
if (u == 0){//防止从0下标导致计算实际长度少1,因为额外的1要用来\0
size = j + 1; //+1是因为分配内存不是从0做下标所以需要判断是否为0
}
else{
size = j;
}
yun = (char*)malloc(size + 1); //多分配额外字节,\0
memset(yun, 0, size + 1);
break;
}
}
int in = 0;
for (int n = u; n <= j; ++n, ++in) {
yun[in] = m_str[n];
}
return yun;
}
}
}
//获取文本多少行
int GetLineNum(char* m_str){
if (m_str == NULL){
return 0;
}
int Size = 0;
for (int i = 0; i <= strlen(m_str)-1; ++i){
if (m_str[i] == '\n'){
++Size;
}
if (m_str[i] == '\0'){
if (m_str[i - 1] != '\n'){
Size++;
}
return Size;
}
}
return Size;
}
//判断文本是否存在
bool JumpTxTExits(char* m_str,char *Str){
if (GetStrTxTIndx(m_str,Str) == 0){
return false;
}
return true;
}
//判断文本在第几行
int GetTxTLineNum(char* m_str,char *Str){
if (Str == NULL || m_str == NULL){
return NULL;
}
char *str1 = NULL;
int i = 1;
int u = GetLineNum(m_str);
while (1){//查找这个文本格式在第几行里
str1 = GetLineTxT(m_str,i);
if (str1 == NULL){
return NULL;
}
if (JumpTxTExits(str1, Str) == true){
break;
}
if (i > u){
return 0;
}
++i;
}
return i;
}
INI读取:
//ini
char* iniGet(char *FileName, char* Primary_Key, char* Key,bool Speck = true){
//判断是否为空
if (Primary_Key == NULL || Key == NULL||FileName == NULL){
return NULL;
}
//格式合成
char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3); //[]\0
memset(FormatStr, 0, strlen(Primary_Key) + 3);
sprintf(FormatStr, "[%s]", Primary_Key);
//读入文件
FILE *fp = fopen(FileName, "r");
if (fp == NULL){
return NULL;
}
fseek(fp, 0L, SEEK_END);
signed long long int size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char *txt = (char*)malloc(size + 1);
memset(txt, 0, size+1);
fread(txt, size, 1, fp);
fclose(fp);
//获取主键值的位置
int y = GetStrTxTIndx(txt, FormatStr);
if (y == 0){
return NULL;
}
//循环读取当前键值下的所有值,除遇得下一个键值
for (int i = y; i <= size-1; ++i){
if (txt[i] == '\n'){
for (int j = i; j <= size - 1; ++j){
if (txt[j] == '['){ //找到了第二个键值
for (int h = j; h <= size - 1; ++h){
txt[h] = '\0';
}
goto t; //读取完成后不要继续读取了,直接跳入下一个处理环境,因为我们已经得到当前主键值下的所有内容了
}
}
}
}
t:
//判断文本在第几行
int Lin = GetTxTLineNum(txt, Key);
if (Lin == 0){
return NULL;
}
//获取所在行文本
char* st = GetLineTxT(txt, Lin);
char* stcopy = (char*)malloc(strlen(st) + 1);
memset(stcopy, 0, strlen(st) + 1);
strcpy(stcopy, st);
free(st);
st = NULL;
int yunsi = 0;
//开始处理
for (int i = 0; i <= strlen(stcopy) - 1; ++i){
if (stcopy[i] == '='){
if (Speck){
if (stcopy[i + 1] == ' '){ //忽略开头空格
i = i + 1;
for (; i <= strlen(stcopy) - 1; ++i){
if (stcopy[i] != ' ')break;
}
i = i - 1;
}
}
for (int j = i + 1; j<=strlen(stcopy)-1; ++j){
++yunsi;
}
char* data = (char*)malloc(yunsi + 1);
if (data == NULL){
return NULL;
}
memset(data, 0, yunsi + 1);
int hk = 0;
for (int j = i + 1; j <= strlen(stcopy) - 1; ++j){
if (stcopy[j] == '\n'){//如果遇到文件尾一样退出
return data;
}
data[hk++] = stcopy[j];
}
return data;
}
}
return 0;
}
示列:
ini:
[key1]
Test = test文本
test=这里是不忽略空格的文本
[key2]
Test=test
代码:
iniGet("file.txt","key1","Test");
输出
test文本
//ini写入
//ini
int iniSet(char *FileName, char* Primary_Key, char* Key, char* Data,bool Speck = true){
if (Primary_Key == NULL || Key == NULL || FileName == NULL){
return NULL;
}
char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3); //[]\0
memset(FormatStr, 0, strlen(Primary_Key) + 3);
sprintf(FormatStr, "[%s]", Primary_Key);
FILE *fp = fopen(FileName, "r");
char* flun = NULL; //用于保存后数据
if (fp == NULL){
return NULL;
}
fseek(fp, 0L, SEEK_END);
signed long long int size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char *txt = (char*)malloc(size + 1);
memset(txt, 0, size + 1);
flun = (char*)malloc(size + 1);
memset(flun, 0, size + 1);
char* jnmhand = (char*)malloc(size + 1+strlen(Data)); //保存头
memset(jnmhand, 0, size + 1 + strlen(Data));
fread(txt, size, 1, fp);
int y = GetStrTxTIndx(txt, FormatStr);
if (y == 0){
return NULL;
}
int yi = 0;
if (y != 1){
for (int i = 0; i <= y - 1; ++i){
jnmhand[i] = txt[i];
}
}
for (int i = y; i <= size - 1; ++i){
flun[yi++] = txt[i-1];
if (txt[i] == '\n'){
for (int j = i; j <= size - 1; ++j){
flun[yi++] = txt[j];
if (txt[j] == '['){ //找到了第二个键值
for (int h = j; h <= size - 1; ++h){
//flun[yi++] = txt[h];
txt[h] = '\0';
}
goto t;
}
}
}
}
t:
int Lin = GetTxTLineNum(flun, Key);
if (Lin == 0){
return NULL;
}
char* setdata = (char*)malloc(size + strlen(Data) + 1);
memset(setdata, 0,size + strlen(Data) + 1);
int nn = 0;
int gh = 0;
bool kj = false; //防止修改数据时再次遇到=
for (int i = 0; i <= strlen(flun) - 1; ++i){
if (flun[i] == '\n'){
++nn;
}
if (nn == Lin - 1){ //代表已经到要修改数据行的头,因为\n在尾
++nn;
for (int j = i; j <= strlen(flun) - 1; ++j){ //寻找=
setdata[gh++] = flun[j];
if (kj == false){
//kj = true;
if (flun[j] == '='){
//寻找有效数据
if (Speck){
j = j + 1;
for (; j <= strlen(flun); ++j){ //寻找有效数据
if (flun[j] != ' '){
break;
}
}
j = j - 1;
i = j;
}
int n = 0;
for (; n <= strlen(Data) - 1; ++n){
setdata[gh++] = Data[n];
}
for (;;){
++i;
if (flun[i] == '\n' || flun[i] == '\0'){
break;
}
}
//i = i + n;
break;
}
}
}
}
setdata[gh++] = flun[i];
}
strcat(jnmhand, setdata);
//内存释放
free(txt);
free(setdata);
//数据写入
fp = fopen(FileName, "w");
if (fp == NULL){
return 0;
}
fwrite(jnmhand, strlen(jnmhand), 1, fp);
fclose(fp);
return 0;
}
用法
iniSet("C:\\Users\\ZZH\\Desktop\\test.ini", "uu", "kk"," k");
完整代码:
#include
#include
#include
//获取文本所在行
int GetStrTxTIndx(char* m_str,const char* Str){
if (m_str == NULL || Str == NULL){
return 0;
}
int StrSize = strlen(Str);
if (StrSize <= 0){
return 0;
}
int Str_m_str = strlen(m_str);
int m_str_index = 0;/*二次循环坐标*/
int y = 0;
for (int i = 0; i <= Str_m_str - 1; i++/*加一是因为i从0开始,下方循环是size+1是为了将坐标移动到下个字符*/){
y = 0;
m_str_index = i;
for (int j = 0; j <= StrSize - 1; ++j, ++m_str_index){
if (Str[j] == m_str[m_str_index]){
y += 1;
}
if (y == StrSize){
return i + 1;
}
if (Str[j] != m_str[m_str_index]){
break;
}
}
}
return 0;
}
//获取一行文本
char* GetLineTxT(char* m_str,int LineIndex = 1) {
if (LineIndex == 0){
return 0;
}
if (m_str == NULL) {
return 0;
}
int l = 0;
char *yun = NULL;
int j = 0;
int u = 0;
for (int i = 0; i <= strlen(m_str) + 1/*包含\0*/; ++i) {
if (m_str[i] == '\n') {
++l;
if (l != LineIndex)
u = i + 1;//+1跳过\n 这里递增1后面已经忽略0因为已经不是第一行坐标
}
if (l == LineIndex) {
//判断此行多长用于分配内存
for (j = u;; ++j) {
if (m_str[j] == '\n' || m_str[j] == '\0') {
int size = 0;
if (u == 0){//防止从0下标导致计算实际长度少1,因为额外的1要用来\0
size = j + 1; //+1是因为分配内存不是从0做下标所以需要判断是否为0
}
else{
size = j;
}
yun = (char*)malloc(size + 1); //多分配额外字节,\0
memset(yun, 0, size + 1);
break;
}
}
int in = 0;
for (int n = u; n <= j; ++n, ++in) {
yun[in] = m_str[n];
}
return yun;
}
}
}
//获取文本多少行
int GetLineNum(char* m_str){
if (m_str == NULL){
return 0;
}
int Size = 0;
for (int i = 0; i <= strlen(m_str)-1; ++i){
if (m_str[i] == '\n'){
++Size;
}
if (m_str[i] == '\0'){
if (m_str[i - 1] != '\n'){
Size++;
}
return Size;
}
}
return Size;
}
//判断文本是否存在
bool JumpTxTExits(char* m_str,char *Str){
if (GetStrTxTIndx(m_str,Str) == 0){
return false;
}
return true;
}
//判断文本在第几行
int GetTxTLineNum(char* m_str,char *Str){
if (Str == NULL || m_str == NULL){
return NULL;
}
char *str1 = NULL;
int i = 1;
int u = GetLineNum(m_str);
while (1){//查找这个文本格式在第几行里
str1 = GetLineTxT(m_str,i);
if (str1 == NULL){
return NULL;
}
if (JumpTxTExits(str1, Str) == true){
break;
}
if (i > u){
return 0;
}
++i;
}
return i;
}
//ini
char* iniGet(char *FileName, char* Primary_Key, char* Key,bool Speck = true){
//判断是否为空
if (Primary_Key == NULL || Key == NULL||FileName == NULL){
return NULL;
}
//格式合成
char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3); //[]\0
memset(FormatStr, 0, strlen(Primary_Key) + 3);
sprintf(FormatStr, "[%s]", Primary_Key);
//读入文件
FILE *fp = fopen(FileName, "r");
if (fp == NULL){
return NULL;
}
fseek(fp, 0L, SEEK_END);
signed long long int size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char *txt = (char*)malloc(size + 1);
memset(txt, 0, size+1);
fread(txt, size, 1, fp);
fclose(fp);
//获取主键值的位置
int y = GetStrTxTIndx(txt, FormatStr);
if (y == 0){
return NULL;
}
//循环读取当前键值下的所有值,除遇得下一个键值
for (int i = y; i <= size-1; ++i){
if (txt[i] == '\n'){
for (int j = i; j <= size - 1; ++j){
if (txt[j] == '['){ //找到了第二个键值
for (int h = j; h <= size - 1; ++h){
txt[h] = '\0';
}
goto t; //读取完成后不要继续读取了,直接跳入下一个处理环境,因为我们已经得到当前主键值下的所有内容了
}
}
}
}
t:
//判断文本在第几行
int Lin = GetTxTLineNum(txt, Key);
if (Lin == 0){
return NULL;
}
//获取所在行文本
char* st = GetLineTxT(txt, Lin);
char* stcopy = (char*)malloc(strlen(st) + 1);
memset(stcopy, 0, strlen(st) + 1);
strcpy(stcopy, st);
free(st);
st = NULL;
int yunsi = 0;
//开始处理
for (int i = 0; i <= strlen(stcopy) - 1; ++i){
if (stcopy[i] == '='){
if (Speck){
if (stcopy[i + 1] == ' '){ //忽略开头空格
i = i + 1;
for (; i <= strlen(stcopy) - 1; ++i){
if (stcopy[i] != ' ')break;
}
i = i - 1;
}
}
for (int j = i + 1; j<=strlen(stcopy)-1; ++j){
++yunsi;
}
char* data = (char*)malloc(yunsi + 1);
if (data == NULL){
return NULL;
}
memset(data, 0, yunsi + 1);
int hk = 0;
for (int j = i + 1; j <= strlen(stcopy) - 1; ++j){
if (stcopy[j] == '\n'){//如果遇到文件尾一样退出
return data;
}
data[hk++] = stcopy[j];
}
return data;
}
}
return 0;
}
//ini
int iniSet(char *FileName, char* Primary_Key, char* Key, char* Data,bool Speck = true){
if (Primary_Key == NULL || Key == NULL || FileName == NULL){
return NULL;
}
char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3); //[]\0
memset(FormatStr, 0, strlen(Primary_Key) + 3);
sprintf(FormatStr, "[%s]", Primary_Key);
FILE *fp = fopen(FileName, "r");
char* flun = NULL; //用于保存后数据
if (fp == NULL){
return NULL;
}
fseek(fp, 0L, SEEK_END);
signed long long int size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char *txt = (char*)malloc(size + 1);
memset(txt, 0, size + 1);
flun = (char*)malloc(size + 1);
memset(flun, 0, size + 1);
char* jnmhand = (char*)malloc(size + 1+strlen(Data)); //保存头
memset(jnmhand, 0, size + 1 + strlen(Data));
fread(txt, size, 1, fp);
int y = GetStrTxTIndx(txt, FormatStr);
if (y == 0){
return NULL;
}
int yi = 0;
if (y != 1){
for (int i = 0; i <= y - 1; ++i){
jnmhand[i] = txt[i];
}
}
for (int i = y; i <= size - 1; ++i){
flun[yi++] = txt[i-1];
if (txt[i] == '\n'){
for (int j = i; j <= size - 1; ++j){
flun[yi++] = txt[j];
if (txt[j] == '['){ //找到了第二个键值
for (int h = j; h <= size - 1; ++h){
//flun[yi++] = txt[h];
txt[h] = '\0';
}
goto t;
}
}
}
}
t:
int Lin = GetTxTLineNum(flun, Key);
if (Lin == 0){
return NULL;
}
char* setdata = (char*)malloc(size + strlen(Data) + 1);
memset(setdata, 0,size + strlen(Data) + 1);
int nn = 0;
int gh = 0;
bool kj = false; //防止修改数据时再次遇到=
for (int i = 0; i <= strlen(flun) - 1; ++i){
if (flun[i] == '\n'){
++nn;
}
if (nn == Lin - 1){ //代表已经到要修改数据行的头,因为\n在尾
++nn;
for (int j = i; j <= strlen(flun) - 1; ++j){ //寻找=
setdata[gh++] = flun[j];
if (kj == false){
//kj = true;
if (flun[j] == '='){
//寻找有效数据
if (Speck){
j = j + 1;
for (; j <= strlen(flun); ++j){ //寻找有效数据
if (flun[j] != ' '){
break;
}
}
j = j - 1;
i = j;
}
int n = 0;
for (; n <= strlen(Data) - 1; ++n){
setdata[gh++] = Data[n];
}
for (;;){
++i;
if (flun[i] == '\n' || flun[i] == '\0'){
break;
}
}
//i = i + n;
break;
}
}
}
}
setdata[gh++] = flun[i];
}
strcat(jnmhand, setdata);
//内存释放
free(txt);
free(setdata);
//数据写入
fp = fopen(FileName, "w");
if (fp == NULL){
return 0;
}
fwrite(jnmhand, strlen(jnmhand), 1, fp);
fclose(fp);
return 0;
}
int main()
{
iniSet("C:\\Users\\ZZH\\Desktop\\test.ini", "uu", "kk"," k");
getchar();
return 0;
}