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





Я никогда не разбирал 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 ().
Они устарели, потому что MS не хочет, чтобы вы больше использовали ini-файлы, они по-прежнему идеальны, если вы действительно хотите читать или записывать такие файлы.
Если вы не планируете делать приложение кроссплатформенным, использование вызовов Windows API было бы лучшим способом. Просто проигнорируйте примечание в документации API о том, что оно предоставляется только для совместимости с 16-битными приложениями.
Если вам нужно кроссплатформенное решение, попробуйте библиотеку Boost Опции программы.
я бы тоже предложил эту библиотеку
это путь, я не понимаю, почему люди просто голосуют за не очень общий ответ.
@Gollum, похоже, что Windows - это заданная зависимость. Использование библиотеки параметров программы означает принятие другой зависимости. Иногда это не имеет большого значения, иногда это так.
Параметры программы Boost, похоже, используют собственный формат конфигурации, знак решетки (#) используется для комментариев (вместо точки с запятой) boost.org/doc/libs/1_57_0/doc/html/program_options/…
@malat Вот почему я бы рекомендовал вместо этого Дерево свойств Boost.
@malat Я запутался, я не упомянул голосование против?
@sjdowling сделайте глубокий вдох, перечитайте ответ OP, затем перечитайте свой фактический ответ и затем угадайте, какую библиотеку INI я сейчас использую: Параметры программы или Дерево свойств.
@RamadheerSingh есть ли шанс, что вы знаете, можно ли использовать параметры программы без поддержки исключений?
Он пытается прочитать существующий файл INI. Использование boost не является ответом, потому что он использует формат, подобный INI.
Я использую SimpleIni. Это кроссплатформенный.
SimpleIni теперь размещен на Github.
Вы пробовали 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(), что может быть сюрпризом), и это уничтожает комментарии и порядок, в котором переменные были определены ранее ...
Если вас интересует переносимость платформы, вы также можете попробовать 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 строк для использования.
GetPrivateProfileInt () и другие функции не рекомендуются MSDN, поскольку они устарели и по-прежнему предоставляются только для обратной совместимости со старыми 16-разрядными системами. Вместо этого используйте другой подход. msdn.microsoft.com/en-us/library/windows/desktop/…