Який найпростіший спосіб проаналізувати файл INI у C ++?


89

Я намагаюся проаналізувати файл INI за допомогою C ++. Будь-які поради щодо найкращого способу досягнення цього? Чи слід використовувати інструменти Windows API для обробки файлів INI (з якими я абсолютно не знайомий), рішення з відкритим кодом чи намагатися проаналізувати його вручну?

Відповіді:


112

Ви можете використовувати функції Windows API, такі як GetPrivateProfileString () та GetPrivateProfileInt () .


4
GetPrivateProfileInt () та інші функції не рекомендуються MSDN, оскільки вони застаріли і все ще надаються лише для сумісності зі старими, 16-розрядними системами. Замість цього використовуйте інший підхід. msdn.microsoft.com/en-us/library/windows/desktop/…
Здено Павлік

Вони застаріли, оскільки MS не хоче, щоб ви більше використовували файли ini, вони все ще ідеальні, якщо ви насправді хочете читати або писати такі файли.
Ніл

114

Якщо вам потрібне міжплатформене рішення, спробуйте бібліотеку параметрів програми Boost .


1
я б запропонував і цю бібліотеку
varnie

21
це шлях, я не розумію, чому люди просто голосують за не дуже загальну відповідь.
Ramadheer Singh

17
@Gollum, схоже, Windows є даною залежністю. Використання бібліотеки Параметри програми означає прийняття іншої залежності. Іноді це не велика справа, іноді це так.
IJ Kennedy,

5
@malat Я розгублений, я не згадав про голосування?
sjdowling

2
Він намагається прочитати існуючий файл INI. Використання boost не є відповіддю, оскільки він використовує формат, подібний до INI.
Лотар

22

Я ніколи не аналізував файли 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

Удачі :)


16

Якщо ви вже використовуєте Qt

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

Потім прочитайте значення

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

Існує купа інших перетворювачів, які перетворюють ваші значення INI як у стандартні типи, так і в типи Qt. Для отримання додаткової інформації дивіться документацію Qt про QSettings.


Непогано, хоча якщо ви вносите зміни, вони зберігають їх назад у файлі .ini, не кажучи вам насправді (тобто дзвінок деструктора sync(), що може бути несподіванкою), і це знищує коментарі та порядок, у якому змінні були визначені раніше ...
Alexis Wilke


8

це питання трохи застаріле, але я розміщу свою відповідь. Я протестував різні класи INI (їх ви можете побачити на моєму веб-сайті ), а також використовую simpleIni, тому що хочу працювати з файлами INI в обох вікнах та winCE. GetPrivateProfileString () Window працює лише з реєстром на winCE.

Це дуже легко читати за допомогою simpleIni. Ось приклад:

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

6

inih - простий синтаксичний аналізатор ini, написаний на мові C, він також постачається з обгорткою 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";

У автора є також список існуючих бібліотек тут .



3

Якщо вас цікавить портативність платформи, ви також можете спробувати Boost.PropertyTree. Він підтримує ini як формат стійкості, хоча дерево властивостей може бути лише на 1 рівень.


2

Якщо ви не плануєте робити програму крос-платформною, найкращим способом буде використання викликів Windows API. Просто проігноруйте примітку в документації API про те, що вона надається лише для сумісності 16-розрядних програм.



0

Я знаю, що це запитання дуже давнє, але я натрапив на нього, тому що мені потрібна була якась крос-платформа для Linux, win32 ... Я написав функцію нижче, це одна функція, яка може аналізувати файли INI, сподіваюся, іншим це буде корисно.

правила та застереження: buf для синтаксичного аналізу повинен мати рядок із закінченням NULL. Завантажте свій файл ini у рядок масиву символів і викликайте цю функцію, щоб проаналізувати його. Назви розділів повинні мати [] дужки навколо них, наприклад, цей [MySection], також значення та розділи повинні починатися на рядку без пробілів. Він проаналізує файли з Windows \ r \ n або з закінченнями рядків Linux \ n. Коментарі повинні використовувати # або // і починатись у верхній частині файлу, жодні коментарі не повинні змішуватися з даними входу INI. Цитати та галочки обрізаються з обох кінців зворотного рядка. Пробіли обрізаються лише в тому випадку, якщо вони виходять за межі цитати. Рядки не повинні мати лапок, а пробіли обрізаються, якщо лапки відсутні. Ви також можете витягти числа або інші дані, наприклад, якщо у вас є плаваюча операція, просто виконайте atof (ret) на буфері 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
}

Як використовувати ... приклад ....

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
}

0

У підсумку я використав inipp, про який не згадується в цій темі.

https://github.com/mcmtroffaes/inipp

Було лише реалізацією ліцензованого заголовка MIT, яку було досить просто додати до проекту та використати 4 рядки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.