在c++中解析INI文件最简单的方法是什么?

时间:2022-12-02 14:09:31

I'm trying to parse an INI file using C++. Any tips on what is the best way to achieve this? Should I use the Windows API tools for INI file processing (with which I am totally unfamiliar), an open-source solution or attempt to parse it manually?

我正在尝试使用c++解析INI文件。有什么建议可以达到这个目的?我是应该使用Windows API工具进行INI文件处理(我完全不熟悉)、开源解决方案还是尝试手工解析?

12 个解决方案

#1


106  

You can use the Windows API functions, such as GetPrivateProfileString() and GetPrivateProfileInt().

您可以使用Windows API函数,如GetPrivateProfileString()和GetPrivateProfileInt()。

#2


110  

If you need a cross-platform solution, try Boost's Program Options library.

如果您需要跨平台的解决方案,请尝试Boost的程序选项库。

#3


23  

I have never parsed ini files, so I can't be too specific on this issue.
But i have one advice:
Don't reinvent the wheel as long as an existing one meets your requirements

我从来没有解析过ini文件,所以在这个问题上我不能太具体。但我有一个建议:只要现有的*符合你的要求,就不要重新发明*

http://en.wikipedia.org/wiki/INI_file#Accessing_INI_files
http://sdl-cfg.sourceforge.net/
http://sourceforge.net/projects/libini/
http://www.codeproject.com/KB/files/config-file-parser.aspx

http://en.wikipedia.org/wiki/INI_file Accessing_INI_files http://sdl-cfg.sourceforge.net/ http://sourceforge.net/projects/libini/ http://sourceforge.net/projects/libini/

Good luck :)

祝你好运:)

#4


16  

I use SimpleIni. It's cross-platform.

我使用SimpleIni。它是跨平台的。

#5


14  

If you are already using Qt

如果您已经在使用Qt

QSettings my_settings("filename.ini", QSettings::IniFormat);

Then read a value

然后读值

my_settings.value("GroupName/ValueName", <<DEFAULT_VAL>>).toInt()

There are a bunch of other converter that convert your INI values into both standard types and Qt types. See Qt documentation on QSettings for more information.

有许多其他转换器将INI值转换为标准类型和Qt类型。有关更多信息,请参阅QSettings方面的Qt文档。

#6


8  

this question is a bit old, but I will post my answer. I have tested various INI classes (you can see them on my website) and I also use simpleIni because I want to work with INI files on both windows and winCE. Window's GetPrivateProfileString() works only with the registry on winCE.

这个问题有点过时了,但我将把我的答案贴出来。我测试了各种INI类(您可以在我的网站上看到它们),我还使用simpleIni,因为我想在windows和winCE上使用INI文件。窗口的GetPrivateProfileString()仅在winCE上与注册表一起工作。

It is very easy to read with simpleIni. Here is an example:

用simpleIni读起来很容易。这是一个例子:

#include "SimpleIni\SimpleIni.h"    
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile(FileName);
const char * pVal = ini.GetValue(section, entry, DefaultStr);

#7


5  

inih is a simple ini parser written in C, it comes with a C++ wrapper too. Example usage:

inih是用C编写的一个简单的ini解析器,它还附带一个c++包装器。使用示例:

#include "INIReader.h"    

INIReader reader("test.ini");

std::cout << "version="
          << reader.GetInteger("protocol", "version", -1) << ", name="
          << reader.Get("user", "name", "UNKNOWN") << ", active="
          << reader.GetBoolean("user", "active", true) << "\n";

The author has also a list of existing libraries here.

作者也有一个现有图书馆的列表。

#8


4  

Have you tried libconfig; very JSON-like syntax. I prefer it over XML configuration files.

你有试过libconfig;非常类json的语法。与XML配置文件相比,我更喜欢它。

#9


3  

If you are interested in platform portability, you can also try Boost.PropertyTree. It supports ini as persistancy format, though the property tree my be 1 level deep only.

如果您对平台可移植性感兴趣,您也可以尝试Boost.PropertyTree。它支持ini作为持久化格式,虽然属性树只有1层深。

#10


2  

Unless you plan on making the app cross-platform, using the Windows API calls would be the best way to go. Just ignore the note in the API documentation about being provided only for 16-bit app compatibility.

除非你计划让应用跨平台,否则使用Windows API调用将是最好的方式。只需忽略API文档中关于只提供16位应用程序兼容性的说明。

#11


1  

Maybe a late answer..But, worth knowing options..If you need a cross-platform solution , definitely you can try GLIB,, its interesting.. (https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

也许晚回答. .但是,值得了解的选择. .如果你需要一个跨平台的解决方案,你当然可以试试GLIB,它很有趣。(https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

#12


0  

I know this question is very old, but I came upon it because I needed something cross platform for linux, win32... I wrote the function below, it is a single function that can parse INI files, hopefully others will find it useful.

我知道这个问题很老了,但我遇到它是因为我需要linux的跨平台,win32……我写了下面的函数,它是一个可以解析INI文件的函数,希望其他人会发现它有用。

rules & caveats: buf to parse must be a NULL terminated string. Load your ini file into a char array string and call this function to parse it. section names must have [] brackets around them, such as this [MySection], also values and sections must begin on a line without leading spaces. It will parse files with Windows \r\n or with Linux \n line endings. Comments should use # or // and begin at the top of the file, no comments should be mixed with INI entry data. Quotes and ticks are trimmed from both ends of the return string. Spaces are only trimmed if they are outside of the quote. Strings are not required to have quotes, and whitespaces are trimmed if quotes are missing. You can also extract numbers or other data, for example if you have a float just perform a atof(ret) on the ret buffer.

规则和警告:buf解析必须是一个空终止字符串。将ini文件加载到一个char数组字符串中,并调用这个函数来解析它。区段名称必须有[]括号,例如这个[MySection],而且值和区段必须在没有前导空格的直线上开始。它将解析带有Windows \r\n或带有Linux \n行结尾的文件。注释应该使用#或/,从文件的顶部开始,不应该将注释与INI条目数据混合。引号和勾号从返回字符串的两端删除。空格只有在引用之外才会被调整。字符串不需要有引号,如果缺少引号,空格也会被删除。您还可以提取数字或其他数据,例如,如果您有一个浮点数,只需在ret缓冲区上执行atof(ret)。

//  -----note: no escape is nessesary for inner quotes or ticks-----
//  -----------------------------example----------------------------
//  [Entry2]
//  Alignment   = 1
//  LightLvl=128
//  Library     = 5555
//  StrValA =  Inner "quoted" or 'quoted' strings are ok to use
//  StrValB =  "This a "quoted" or 'quoted' String Value"
//  StrValC =  'This a "tick" or 'tick' String Value'
//  StrValD =  "Missing quote at end will still work
//  StrValE =  This is another "quote" example
//  StrValF =  "  Spaces inside the quote are preserved "
//  StrValG =  This works too and spaces are trimmed away
//  StrValH =
//  ----------------------------------------------------------------
//12oClocker super lean and mean INI file parser (with section support)
//set section to 0 to disable section support
//returns TRUE if we were able to extract a string into ret value
//NextSection is a char* pointer, will be set to zero if no next section is found
//will be set to pointer of next section if it was found.
//use it like this... char* NextSection = 0;  GrabIniValue(X,X,X,X,X,&NextSection);
//buf is data to parse, ret is the user supplied return buffer
BOOL GrabIniValue(char* buf, const char* section, const char* valname, char* ret, int retbuflen, char** NextSection)
{
    if(!buf){*ret=0; return FALSE;}

    char* s = buf; //search starts at "s" pointer
    char* e = 0;   //end of section pointer

    //find section
    if(section)
    {
        int L = strlen(section);
        SearchAgain1:
        s = strstr(s,section); if(!s){*ret=0; return FALSE;}    //find section
        if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain1;} //section must be at begining of a line!
        s+=L;                                                   //found section, skip past section name
        while(*s!='\n'){s++;} s++;                              //spin until next line, s is now begining of section data
        e = strstr(s,"\n[");                                    //find begining of next section or end of file
        if(e){*e=0;}                                            //if we found begining of next section, null the \n so we don't search past section
        if(NextSection)                                         //user passed in a NextSection pointer
        { if(e){*NextSection=(e+1);}else{*NextSection=0;} }     //set pointer to next section
    }

    //restore char at end of section, ret=empty_string, return FALSE
    #define RESTORE_E     if(e){*e='\n';}
    #define SAFE_RETURN   RESTORE_E;  (*ret)=0;  return FALSE

    //find valname
    int L = strlen(valname);
    SearchAgain2:
    s = strstr(s,valname); if(!s){SAFE_RETURN;}             //find valname
    if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain2;} //valname must be at begining of a line!
    s+=L;                                                   //found valname match, skip past it
    while(*s==' ' || *s == '\t'){s++;}                      //skip spaces and tabs
    if(!(*s)){SAFE_RETURN;}                                 //if NULL encounted do safe return
    if(*s != '='){goto SearchAgain2;}                       //no equal sign found after valname, search again
    s++;                                                    //skip past the equal sign
    while(*s==' '  || *s=='\t'){s++;}                       //skip spaces and tabs
    while(*s=='\"' || *s=='\''){s++;}                       //skip past quotes and ticks
    if(!(*s)){SAFE_RETURN;}                                 //if NULL encounted do safe return
    char* E = s;                                            //s is now the begining of the valname data
    while(*E!='\r' && *E!='\n' && *E!=0){E++;} E--;         //find end of line or end of string, then backup 1 char
    while(E > s && (*E==' ' || *E=='\t')){E--;}             //move backwards past spaces and tabs
    while(E > s && (*E=='\"' || *E=='\'')){E--;}            //move backwards past quotes and ticks
    L = E-s+1;                                              //length of string to extract NOT including NULL
    if(L<1 || L+1 > retbuflen){SAFE_RETURN;}                //empty string or buffer size too small
    strncpy(ret,s,L);                                       //copy the string
    ret[L]=0;                                               //null last char on return buffer
    RESTORE_E;
    return TRUE;

    #undef RESTORE_E
    #undef SAFE_RETURN
}

How to use... example....

如何使用…例子....

char sFileData[] = "[MySection]\r\n"
"MyValue1 = 123\r\n"
"MyValue2 = 456\r\n"
"MyValue3 = 789\r\n"
"\r\n"
"[MySection]\r\n"
"MyValue1 = Hello1\r\n"
"MyValue2 = Hello2\r\n"
"MyValue3 = Hello3\r\n"
"\r\n";
char str[256];
char* sSec = sFileData;
char secName[] = "[MySection]"; //we support sections with same name
while(sSec)//while we have a valid sNextSec
{
    //print values of the sections
    char* next=0;//in case we dont have any sucessful grabs
    if(GrabIniValue(sSec,secName,"MyValue1",str,sizeof(str),&next)) { printf("MyValue1 = [%s]\n",str); }
    if(GrabIniValue(sSec,secName,"MyValue2",str,sizeof(str),0))     { printf("MyValue2 = [%s]\n",str); }
    if(GrabIniValue(sSec,secName,"MyValue3",str,sizeof(str),0))     { printf("MyValue3 = [%s]\n",str); }
    printf("\n");
    sSec = next; //parse next section, next will be null if no more sections to parse
}

#1


106  

You can use the Windows API functions, such as GetPrivateProfileString() and GetPrivateProfileInt().

您可以使用Windows API函数,如GetPrivateProfileString()和GetPrivateProfileInt()。

#2


110  

If you need a cross-platform solution, try Boost's Program Options library.

如果您需要跨平台的解决方案,请尝试Boost的程序选项库。

#3


23  

I have never parsed ini files, so I can't be too specific on this issue.
But i have one advice:
Don't reinvent the wheel as long as an existing one meets your requirements

我从来没有解析过ini文件,所以在这个问题上我不能太具体。但我有一个建议:只要现有的*符合你的要求,就不要重新发明*

http://en.wikipedia.org/wiki/INI_file#Accessing_INI_files
http://sdl-cfg.sourceforge.net/
http://sourceforge.net/projects/libini/
http://www.codeproject.com/KB/files/config-file-parser.aspx

http://en.wikipedia.org/wiki/INI_file Accessing_INI_files http://sdl-cfg.sourceforge.net/ http://sourceforge.net/projects/libini/ http://sourceforge.net/projects/libini/

Good luck :)

祝你好运:)

#4


16  

I use SimpleIni. It's cross-platform.

我使用SimpleIni。它是跨平台的。

#5


14  

If you are already using Qt

如果您已经在使用Qt

QSettings my_settings("filename.ini", QSettings::IniFormat);

Then read a value

然后读值

my_settings.value("GroupName/ValueName", <<DEFAULT_VAL>>).toInt()

There are a bunch of other converter that convert your INI values into both standard types and Qt types. See Qt documentation on QSettings for more information.

有许多其他转换器将INI值转换为标准类型和Qt类型。有关更多信息,请参阅QSettings方面的Qt文档。

#6


8  

this question is a bit old, but I will post my answer. I have tested various INI classes (you can see them on my website) and I also use simpleIni because I want to work with INI files on both windows and winCE. Window's GetPrivateProfileString() works only with the registry on winCE.

这个问题有点过时了,但我将把我的答案贴出来。我测试了各种INI类(您可以在我的网站上看到它们),我还使用simpleIni,因为我想在windows和winCE上使用INI文件。窗口的GetPrivateProfileString()仅在winCE上与注册表一起工作。

It is very easy to read with simpleIni. Here is an example:

用simpleIni读起来很容易。这是一个例子:

#include "SimpleIni\SimpleIni.h"    
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile(FileName);
const char * pVal = ini.GetValue(section, entry, DefaultStr);

#7


5  

inih is a simple ini parser written in C, it comes with a C++ wrapper too. Example usage:

inih是用C编写的一个简单的ini解析器,它还附带一个c++包装器。使用示例:

#include "INIReader.h"    

INIReader reader("test.ini");

std::cout << "version="
          << reader.GetInteger("protocol", "version", -1) << ", name="
          << reader.Get("user", "name", "UNKNOWN") << ", active="
          << reader.GetBoolean("user", "active", true) << "\n";

The author has also a list of existing libraries here.

作者也有一个现有图书馆的列表。

#8


4  

Have you tried libconfig; very JSON-like syntax. I prefer it over XML configuration files.

你有试过libconfig;非常类json的语法。与XML配置文件相比,我更喜欢它。

#9


3  

If you are interested in platform portability, you can also try Boost.PropertyTree. It supports ini as persistancy format, though the property tree my be 1 level deep only.

如果您对平台可移植性感兴趣,您也可以尝试Boost.PropertyTree。它支持ini作为持久化格式,虽然属性树只有1层深。

#10


2  

Unless you plan on making the app cross-platform, using the Windows API calls would be the best way to go. Just ignore the note in the API documentation about being provided only for 16-bit app compatibility.

除非你计划让应用跨平台,否则使用Windows API调用将是最好的方式。只需忽略API文档中关于只提供16位应用程序兼容性的说明。

#11


1  

Maybe a late answer..But, worth knowing options..If you need a cross-platform solution , definitely you can try GLIB,, its interesting.. (https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

也许晚回答. .但是,值得了解的选择. .如果你需要一个跨平台的解决方案,你当然可以试试GLIB,它很有趣。(https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

#12


0  

I know this question is very old, but I came upon it because I needed something cross platform for linux, win32... I wrote the function below, it is a single function that can parse INI files, hopefully others will find it useful.

我知道这个问题很老了,但我遇到它是因为我需要linux的跨平台,win32……我写了下面的函数,它是一个可以解析INI文件的函数,希望其他人会发现它有用。

rules & caveats: buf to parse must be a NULL terminated string. Load your ini file into a char array string and call this function to parse it. section names must have [] brackets around them, such as this [MySection], also values and sections must begin on a line without leading spaces. It will parse files with Windows \r\n or with Linux \n line endings. Comments should use # or // and begin at the top of the file, no comments should be mixed with INI entry data. Quotes and ticks are trimmed from both ends of the return string. Spaces are only trimmed if they are outside of the quote. Strings are not required to have quotes, and whitespaces are trimmed if quotes are missing. You can also extract numbers or other data, for example if you have a float just perform a atof(ret) on the ret buffer.

规则和警告:buf解析必须是一个空终止字符串。将ini文件加载到一个char数组字符串中,并调用这个函数来解析它。区段名称必须有[]括号,例如这个[MySection],而且值和区段必须在没有前导空格的直线上开始。它将解析带有Windows \r\n或带有Linux \n行结尾的文件。注释应该使用#或/,从文件的顶部开始,不应该将注释与INI条目数据混合。引号和勾号从返回字符串的两端删除。空格只有在引用之外才会被调整。字符串不需要有引号,如果缺少引号,空格也会被删除。您还可以提取数字或其他数据,例如,如果您有一个浮点数,只需在ret缓冲区上执行atof(ret)。

//  -----note: no escape is nessesary for inner quotes or ticks-----
//  -----------------------------example----------------------------
//  [Entry2]
//  Alignment   = 1
//  LightLvl=128
//  Library     = 5555
//  StrValA =  Inner "quoted" or 'quoted' strings are ok to use
//  StrValB =  "This a "quoted" or 'quoted' String Value"
//  StrValC =  'This a "tick" or 'tick' String Value'
//  StrValD =  "Missing quote at end will still work
//  StrValE =  This is another "quote" example
//  StrValF =  "  Spaces inside the quote are preserved "
//  StrValG =  This works too and spaces are trimmed away
//  StrValH =
//  ----------------------------------------------------------------
//12oClocker super lean and mean INI file parser (with section support)
//set section to 0 to disable section support
//returns TRUE if we were able to extract a string into ret value
//NextSection is a char* pointer, will be set to zero if no next section is found
//will be set to pointer of next section if it was found.
//use it like this... char* NextSection = 0;  GrabIniValue(X,X,X,X,X,&NextSection);
//buf is data to parse, ret is the user supplied return buffer
BOOL GrabIniValue(char* buf, const char* section, const char* valname, char* ret, int retbuflen, char** NextSection)
{
    if(!buf){*ret=0; return FALSE;}

    char* s = buf; //search starts at "s" pointer
    char* e = 0;   //end of section pointer

    //find section
    if(section)
    {
        int L = strlen(section);
        SearchAgain1:
        s = strstr(s,section); if(!s){*ret=0; return FALSE;}    //find section
        if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain1;} //section must be at begining of a line!
        s+=L;                                                   //found section, skip past section name
        while(*s!='\n'){s++;} s++;                              //spin until next line, s is now begining of section data
        e = strstr(s,"\n[");                                    //find begining of next section or end of file
        if(e){*e=0;}                                            //if we found begining of next section, null the \n so we don't search past section
        if(NextSection)                                         //user passed in a NextSection pointer
        { if(e){*NextSection=(e+1);}else{*NextSection=0;} }     //set pointer to next section
    }

    //restore char at end of section, ret=empty_string, return FALSE
    #define RESTORE_E     if(e){*e='\n';}
    #define SAFE_RETURN   RESTORE_E;  (*ret)=0;  return FALSE

    //find valname
    int L = strlen(valname);
    SearchAgain2:
    s = strstr(s,valname); if(!s){SAFE_RETURN;}             //find valname
    if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain2;} //valname must be at begining of a line!
    s+=L;                                                   //found valname match, skip past it
    while(*s==' ' || *s == '\t'){s++;}                      //skip spaces and tabs
    if(!(*s)){SAFE_RETURN;}                                 //if NULL encounted do safe return
    if(*s != '='){goto SearchAgain2;}                       //no equal sign found after valname, search again
    s++;                                                    //skip past the equal sign
    while(*s==' '  || *s=='\t'){s++;}                       //skip spaces and tabs
    while(*s=='\"' || *s=='\''){s++;}                       //skip past quotes and ticks
    if(!(*s)){SAFE_RETURN;}                                 //if NULL encounted do safe return
    char* E = s;                                            //s is now the begining of the valname data
    while(*E!='\r' && *E!='\n' && *E!=0){E++;} E--;         //find end of line or end of string, then backup 1 char
    while(E > s && (*E==' ' || *E=='\t')){E--;}             //move backwards past spaces and tabs
    while(E > s && (*E=='\"' || *E=='\'')){E--;}            //move backwards past quotes and ticks
    L = E-s+1;                                              //length of string to extract NOT including NULL
    if(L<1 || L+1 > retbuflen){SAFE_RETURN;}                //empty string or buffer size too small
    strncpy(ret,s,L);                                       //copy the string
    ret[L]=0;                                               //null last char on return buffer
    RESTORE_E;
    return TRUE;

    #undef RESTORE_E
    #undef SAFE_RETURN
}

How to use... example....

如何使用…例子....

char sFileData[] = "[MySection]\r\n"
"MyValue1 = 123\r\n"
"MyValue2 = 456\r\n"
"MyValue3 = 789\r\n"
"\r\n"
"[MySection]\r\n"
"MyValue1 = Hello1\r\n"
"MyValue2 = Hello2\r\n"
"MyValue3 = Hello3\r\n"
"\r\n";
char str[256];
char* sSec = sFileData;
char secName[] = "[MySection]"; //we support sections with same name
while(sSec)//while we have a valid sNextSec
{
    //print values of the sections
    char* next=0;//in case we dont have any sucessful grabs
    if(GrabIniValue(sSec,secName,"MyValue1",str,sizeof(str),&next)) { printf("MyValue1 = [%s]\n",str); }
    if(GrabIniValue(sSec,secName,"MyValue2",str,sizeof(str),0))     { printf("MyValue2 = [%s]\n",str); }
    if(GrabIniValue(sSec,secName,"MyValue3",str,sizeof(str),0))     { printf("MyValue3 = [%s]\n",str); }
    printf("\n");
    sSec = next; //parse next section, next will be null if no more sections to parse
}