Каков самый простой способ разобрать файл INI на C++?

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
90
0
126 723
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Я никогда не разбирал 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

Удачи :)

Ответ принят как подходящий

Вы можете использовать функции Windows API, такие как GetPrivateProfileString () и GetPrivateProfileInt ().

GetPrivateProfileInt () и другие функции не рекомендуются MSDN, поскольку они устарели и по-прежнему предоставляются только для обратной совместимости со старыми 16-разрядными системами. Вместо этого используйте другой подход. msdn.microsoft.com/en-us/library/windows/desktop/…

Zdeno Pavlik 21.02.2018 13:59

Они устарели, потому что MS не хочет, чтобы вы больше использовали ini-файлы, они по-прежнему идеальны, если вы действительно хотите читать или записывать такие файлы.

Neil 12.07.2020 09:05

Если вы не планируете делать приложение кроссплатформенным, использование вызовов Windows API было бы лучшим способом. Просто проигнорируйте примечание в документации API о том, что оно предоставляется только для совместимости с 16-битными приложениями.

Если вам нужно кроссплатформенное решение, попробуйте библиотеку Boost Опции программы.

я бы тоже предложил эту библиотеку

varnie 04.11.2009 13:31

это путь, я не понимаю, почему люди просто голосуют за не очень общий ответ.

Ramadheer Singh 15.07.2010 02:49

@Gollum, похоже, что Windows - это заданная зависимость. Использование библиотеки параметров программы означает принятие другой зависимости. Иногда это не имеет большого значения, иногда это так.

I. J. Kennedy 28.06.2011 05:39

Параметры программы Boost, похоже, используют собственный формат конфигурации, знак решетки (#) используется для комментариев (вместо точки с запятой) boost.org/doc/libs/1_57_0/doc/html/program_options/…

malat 17.11.2014 20:24

@malat Вот почему я бы рекомендовал вместо этого Дерево свойств Boost.

sjdowling 12.01.2015 16:45

@malat Я запутался, я не упомянул голосование против?

sjdowling 12.01.2015 16:49

@sjdowling сделайте глубокий вдох, перечитайте ответ OP, затем перечитайте свой фактический ответ и затем угадайте, какую библиотеку INI я сейчас использую: Параметры программы или Дерево свойств.

malat 12.01.2015 16:51

@RamadheerSingh есть ли шанс, что вы знаете, можно ли использовать параметры программы без поддержки исключений?

Tarc 13.07.2015 22:52

Он пытается прочитать существующий файл INI. Использование boost не является ответом, потому что он использует формат, подобный INI.

Lothar 03.12.2015 05:30

Я использую SimpleIni. Это кроссплатформенный.

SimpleIni теперь размещен на Github.

Richard Ye 14.11.2014 05:24

Вы пробовали libconfig; очень похожий на JSON синтаксис. Я предпочитаю его файлам конфигурации XML.

этот вопрос немного устарел, но я опубликую свой ответ. Я протестировал различные классы INI (вы можете увидеть их на моем интернет сайт), и я также использую simpleIni, потому что хочу работать с файлами INI как в Windows, так и в winCE. GetPrivateProfileString () окна работает только с реестром на winCE.

С simpleIni очень легко читать. Вот пример:

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

Если вы уже используете Qt

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

Затем прочтите значение

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

Существует множество других конвертеров, которые преобразуют ваши значения INI как в стандартные типы, так и в типы Qt. Дополнительную информацию смотрите в документации Qt по QSettings.

Неплохо, хотя, если вы вносите изменения, они сохраняют их обратно в файл .ini, не сообщая вам об этом (т.е. деструктор вызывает sync(), что может быть сюрпризом), и это уничтожает комментарии и порядок, в котором переменные были определены ранее ...

Alexis Wilke 29.08.2016 05:35

Если вас интересует переносимость платформы, вы также можете попробовать Boost.PropertyTree. Он поддерживает ini как постоянный формат, хотя дерево свойств может быть только на 1 уровень.

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";

У автора также есть список существующих библиотек здесь.

Может быть, поздний ответ .. Но стоит знать варианты .. Если вам нужно кроссплатформенное решение, определенно вы можете попробовать GLIB, это интересно .. (https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

Я знаю, что этот вопрос очень старый, но я столкнулся с ним, потому что мне нужно что-то кросс-платформенное для linux, win32 ... Я написал функцию ниже, это единственная функция, которая может анализировать файлы INI, надеюсь, другие сочтут это полезным.

правила и предостережения: buf для синтаксического анализа должен быть строкой с завершающим NULL. Загрузите ваш ini-файл в строку массива символов и вызовите эту функцию для его анализа. Имена разделов должны заключаться в квадратные скобки [], например, этот [MySection], также значения и разделы должны начинаться со строки без начальных пробелов. Он будет анализировать файлы с Windows \ r \ n или Linux с окончанием строки \ n. Комментарии должны использовать # или // и начинаться с начала файла, никакие комментарии не должны смешиваться с данными записи INI. Котировки и отметки обрезаются с обоих концов возвращаемой строки. Пробелы обрезаются, только если они находятся за пределами цитаты. Строки не обязательно должны содержать кавычки, а пробелы обрезаются, если кавычки отсутствуют. Вы также можете извлекать числа или другие данные, например, если у вас есть float, просто выполните 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
}

В итоге я использовал inipp, который не упоминается в этой теме.

https://github.com/mcmtroffaes/inipp

Это была реализация только заголовков, лицензированная MIT, которая была достаточно простой для добавления в проект и 4 строк для использования.

Другие вопросы по теме