C прочитать ini файл
inih (INI Not Invented Here)
inih (INI Not Invented Here) is a simple .INI file parser written in C. It's only a couple of pages of code, and it was designed to be small and simple, so it's good for embedded systems. It's also more or less compatible with Python's ConfigParser style of .INI files, including RFC 822-style multi-line syntax and name: value entries.
To use it, just give ini_parse() an INI file, and it will call a callback for every name=value pair parsed, giving you strings for the section, name, and value. It's done this way ("SAX style") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation.
You can also call ini_parse_file() to parse directly from a FILE* object, ini_parse_string() to parse data from a string, or ini_parse_stream() to parse using a custom fgets-style reader function for custom I/O.
Download a release, browse the source, or read about how to use inih in a DRY style with X-Macros.
You can control various aspects of inih using preprocessor defines:
- Stop on first error: By default, inih keeps parsing the rest of the file after an error. To stop parsing on the first error, add -DINI_STOP_ON_FIRST_ERROR=1 .
- Report line numbers: By default, the ini_handler callback doesn't receive the line number as a parameter. If you need that, add -DINI_HANDLER_LINENO=1 .
- Call handler on new section: By default, inih only calls the handler on each name=value pair. To detect new sections (e.g., the INI file has multiple sections with the same name), add -DINI_CALL_HANDLER_ON_NEW_SECTION=1 . Your handler function will then be called each time a new section is encountered, with section set to the new section name but name and value set to NULL.
- Stack vs heap: By default, inih creates a fixed-sized line buffer on the stack. To allocate on the heap using malloc instead, specify -DINI_USE_STACK=0 .
- Maximum line length: The default maximum line length (for stack or heap) is 200 bytes. To override this, add something like -DINI_MAX_LINE=1000 . Note that INI_MAX_LINE must be 3 more than the longest line (due to \r , \n , and the NUL).
- Initial malloc size: INI_INITIAL_ALLOC specifies the initial malloc size when using the heap. It defaults to 200 bytes.
- Allow realloc: By default when using the heap ( -DINI_USE_STACK=0 ), inih allocates a fixed-sized buffer of INI_INITIAL_ALLOC bytes. To allow this to grow to INI_MAX_LINE bytes, doubling if needed, set -DINI_ALLOW_REALLOC=1 .
- Custom allocator: By default when using the heap, the standard library's malloc , free , and realloc functions are used; to use a custom allocator, specify -DINI_CUSTOM_ALLOCATOR=1 (and -DINI_USE_STACK=0 ). You must define and link functions named ini_malloc , ini_free , and (if INI_ALLOW_REALLOC is set) ini_realloc , which must have the same signatures as the stdlib.h memory allocation functions.
Simple example in C
If you're into C++ and the STL, there is also an easy-to-use INIReader class that stores values in a map and lets you Get() them:
This simple C++ API works fine, but it's not very fully-fledged. I'm not planning to work more on the C++ API at the moment, so if you want a bit more power (for example GetSections() and GetFields() functions), see these forks:
Differences from ConfigParser
Some differences between inih and Python's ConfigParser standard library module:
- INI name=value pairs given above any section headers are treated as valid items with no section (section name is an empty string). In ConfigParser having no section is an error.
- Line continuations are handled with leading whitespace on continued lines (like ConfigParser). However, instead of concatenating continued lines together, they are treated as separate values for the same key (unlike ConfigParser).
- Windows/Win32 uses UTF-16 filenames natively, so to handle Unicode paths you need to call _wfopen() to open a file and then ini_parse_file() to parse it; inih does not include wchar_t or Unicode handling.
- The meson.build file is not required to use or compile inih, its main purpose is for distributions.
- By default Meson is set up for distro installation, but this behavior can be configured for embedded use cases:
- with -Ddefault_library=static static libraries are built.
- with -Ddistro_install=false libraries, headers and pkg-config files won't be installed.
- with -Dwith_INIReader=false you can disable building the C++ library.
Using inih with tipi.build
inih can be easily used in tipi.build projects simply by adding the following entry to your .tipi/deps :
The required include path in your project is:
Building from vcpkg
You can build and install inih using vcpkg dependency manager:
The inih port in vcpkg is kept up to date by microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 months ago .
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
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?
Preface
Firstly, read this MSDN blog post on the limitations of INI files. If it suits your needs, read on.
The tiny class
Add a new class called IniFile.cs to your project:
How to use it
Open the INI file in one of the 3 following ways:
You can write some values like so:
To create a file like this:
To read the values out of the INI file:
Optionally, you can set [Section] 's:
To create a file like this:
You can also check for the existence of a key like so:
You can delete a key like so:
You can also delete a whole section (including all keys) like so:
Please feel free to comment with any improvements!
Maybe a more traditional default would be per-application (not per-assembly) .ini files like Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini")) .
Old now, and as much as I respect Raymond Chen, many of the limitations in that article were limitations of the specific INI library in Windows, and not the INI format itself. Others, like granular permissions, could be easily sidestepped via multiple files. An official, modernized INI library would be most-welcomed, even today.
There are third party solutions available, though.
@aloneguid I would argue that the large set of available features actually contributed to .NET config files ending up being strange behemoths with a lot of magic in them. They have become "code in the config file," and this leads to a lot of complexity, strange behaviors, and makes configuration management more difficult. (I'm looking at you, database "providers" and connection strings.) So INI files are also generally better for non-manual editing, as well.
i like old method (P/Inovke) and you can use unicode with old method like this: File.WriteAllBytes(path, new byte[] < 0xFF, 0xFE >);
Steps to use the Ini class
In your project namespace definition add
Create a INIFile like this
Use IniWriteValue to write a new value to a specific key in a section or use IniReadValue to read a value FROM a key in a specific Section.
this worked for me, and then stopped working from another point. No idea still what went different under the hood
I used this approach for awhile, but security enhancements starting in Win7 have pretty much killed this for me. You can still use this approach, but you will have store the .ini in ProgramData and have your app read / write there.
Do not save application configuration ini files in ProgramData. They do not belong in either the Registry or ProgramData. Config files are supposed to be in the LocalApplicationData folders.
I found this simple implementation:
Works well for what I need.
Here is how you use it:
Here is the code:
The code in joerage's answer is inspiring.
Unfortunately, it changes the character casing of the keys and does not handle comments. So I wrote something that should be robust enough to read (only) very dirty INI files and allows to retrieve keys as they are.
It uses some LINQ, a nested case insensitive string dictionary to store sections, keys and values, and read the file in one go.
Good! At least some changes are required to work better. Line 16: ini[""] = currentSection; To: //ini[""] = currentSection; This must be removed as every time the first element [0] will be an empty segment due to this initialization. Line 36: currentSection[line.Substring(0, idx)] = line.Substring(idx + 1); To: currentSection[line.Substring(0, idx).Trim()] = line.Substring(idx + 1).Trim(); Key and values should be independently trimmed, not only on the line Trim. In INI like configuration files usually who add K->V pairs tend to align these equals inside sections. Thank you!
Wew been à long time. Thanks a lot for your suggestions. They all make sense and deserves this code to have a good refresh.
Sorry for the shameless plug but I hope it can be of help of anyone revisiting this answer.
@scott the issue I'm having is for whatever reason IIS does not recognize it when the app is running. it is deployed, and there, but is not being consumed. HTTP 500.30 returned and the IIS App log says "the configuration file was not found and is not optional."
PeanutButter.INI is a Nuget-packaged class for INI files manipulation. It supports read/write, including comments – your comments are preserved on write. It appears to be reasonably popular, is tested and easy to use. It's also totally free and open-source.
Disclaimer: I am the author of PeanutButter.INI.
@ThomasWeller - I'm not here to argue with people. The Registry should never be used unless it is absolutely necessary. And even then it should be reserved for Microsoft Windows use only. Virtually no third-party software cleans up their Registry keys when you uninstall their software, leaving the Registry in a state of mess, which they should have stayed out of to begin with. INI files, XML files, JSON files, and other configuration file formats designed specifically for this function should be placed into the AppData folder where they are SUPPOSED to go.
If you want just a simple reader without sections and any other dlls here is simple solution:
Try this method:
It creates the dictionary where the key is "-". You can load it like this:
В интернете приведено очень много способов хранения настроек программы, но все они как-то разбросаны, поэтому я решил их собрать вместе и расписать, как этим пользоваться.
На хабре уже была посвящена этому тема, поэтому… перейти
Информация о Properties.Settings
Организация Properties.Settings — это обычный xml файл, который можно найти в папке пользователя:
С:\ Users \ [user name] \ AppData \ Local \ [ (Project Name) or (AssemblyCompany) ] \ [name project_cashBuild] \ [AssemblyVersion] \ user.config
Для начала нам нужно создать такие переменные для Properties.Settings. Перейдем в Properties -> Settings.settings:
Я создал 3-и переменные и выбрал область их использования: 2- область пользователь и 1- приложение.
Различие между областями просты. Область приложения можно только читать, а пользователь — изменять и читать.
Вернемся к переменным:- Version — версия нашей программы. Определил ее строкой и областью приложение. Т.к. версия может содержать буквы (например, b — от beta). А область выбрал, чтоб не менялась наша версия приложения (т.к. AssemblyVersion редко кто использует).
- Save_text — это переменная, куда мы будем сохранять наш текст.
- open_sum — сколько раз мы открыли программу.
Результаты работы программы
Первый запуск, мы видим, что кол-во запусков равно 1. И теста в richTextBox1 нет.
Теперь напишем и сохраним текст.
При втором запуске мы видим, что текст сохранен, и кол-во запусков уже 2-ва.
Очень удобно использовать этот объект, если надо работать в разных областях видимости в одном проекте. Метод хорош, когда вам не надо, чтоб рядовой пользователь рылся в файлах настройки программы.
С ini-файлами все на оборот, они лежат в папке рядом с программой, что позволяет пользователю изменить настройки вне-программы. Данный способ хорош, если настройки программы заносятся вручную. Например, эмулятор для запуска игры без лицензии (тотже revLoader).
Теперь перейдем к нашей теме. Для работы с таким типом файлов, нам нужно создать класс по работе с ним. Создаем класс, например «IniFile», подключаем пространство имен, которых нет:
А теперь разбираем по-порядку:Теперь переходим в основную программу.
Результаты работы программы
При первом запуска, у нас нет файла config.ini. Поэтому при проверке возвращаются fasle и мы приравниваем окно к минимальным параметрам.
Меняем параметры окна и жмем «Применить»
Редактируем файл config.ini руками и жмем загрузить.
На этом все, в следующий раз опишу работу с xml файлами и с бинарными файлами.
Как-то находясь в поиске как мне прикрутить конфигурационные ini файлы или json к моему сервачку перебирал варианты, но почему-то они были неудобны или слишком простые, или велосипеды. И хоть я люблю xml конфигурирование, но порою это чрезмерно огромные файлы и неудобно для небольшого количества настроек писать много текста. Раз задал другу вопрос по этой теме, он то мне и подкинул библиотеку. Напоминает она json в смеси с yaml.
Библиотека имеет два интерфейса: функциональный и объектный. Они очень похожи, так как объектный использует внутри функциональную реализацию, но имеют некоторые различия, рассмотренные в данном посте.
Настройка и подключение
Библиотека есть во многих репозиториях, поэтому установка простая:
В исходниках С++ подключается одним лишь инклудом:Конфигурационный файл
Файл конфига представляет собой следующего вида структуру:
Основными видами записей в конфиге являются такие типы:Элемент (Setting)
Это минимальная значимая часть конфигурационной структуры и имеют вид ключ-значение:
Группы (Groups)
Группы могут содержать любое число элементов, но каждый элемент должен содержать уникальный ключ в пределах группы. Записывается в фигурных скобках:
Массивы (Arrays)
Содержат любое количество элементов, даже ноль, но все элементы состоят лишь из значений и должны иметь один и тот же скалярный тип в пределах массива. Записывает в квадратных скобках:
Списки (Lists)
Списки содержат ноль или более элементов скалярного типа, массивов, групп или списков. Записывается в круглых скобках:
Целочисленые значения (Integers)
Записываются обычным нам десятичным способом (±0-9) или шестнадцатиричном виде (0xA-f). Но целочисленные значения ограничены диапазоном -2147483648..2147483647 (32bit), но если нужны большие диапазоны, то в конце добавляется ’L’.
Дробные числа с плавающей запятой (floats)
Записывается тоже привычным нам способом
Запись с экспонентой стандартная с 'e'.
Булевые значения (Boolean)
Строки (Strings)
Записываются в двойных кавычках как .
Следующие варианты в итоге дадут то же значение строки:Комментарии
Внешние подключения (Includes)
Это, в общем, самая вкусная вкусняшка.
С API
В данной части я не стану расписывать все функции, только лишь основные, так как они в целом похожие, и основные нюансы.
Описание использованых функций ниже
Небольшое описание функционала
config_t — тип файла конфигурации (это ещё не запись). Грубо говоря, основной контейнер.
config_setting_t — объект элемента конфигурации. В примере используется указатель, возвращаемый контейнером на искомый элемент.
int config_read_file(config_t * config, const char * filename) — функция читает конфигурационный файл filename в память и заполняет объект типа config_t. Можно не читать из файла, а сразу «скормить» строку в config_read_string() или отдать дескриптор файла в config_read()
int config_lookup_string (const config_t * config, const char * path, const char ** value) — ищет и возвращает значение в виде указателя на строку value, по заданному пути path внутри конфига config.
config_setting_t * config_lookup (const config_t * config, const char * path) — ищет запись внутри конфига по заданному внутреннему пути и возвращает её.
config_setting_t * config_setting_get_elem (const config_setting_t * setting, unsigned int index) — используется для массивов, списков чтобы возвращать из него элементы с таким-то номером по порядку
int config_setting_lookup_string (const config_setting_t * setting, const char * name, const char ** value) —
возвращает значение value дочернего элемента name относительно заданной записи setting
Когда же надо получить значение в конкретно заданной записи, то используются функции типа
int config_setting_get_int (const config_setting_t * setting)C++ API
Тот же пример, но на С++. Полная документация на сайте
Тут тот же принцип, что и в функциональном стиле, только перед получением данных из конфига необходимо получать корневой элемент cfg.getRoot(); и уже потом от него обращаться к остальным элементам. Так же надо быть внимательным к тому, что практически на все ошибки кидаются исключенияЗаключение
Кроме считывания удобных конфигов, в API предоставлен так же функционал создания элементов конфига и его записи на носитель.
Всё в документации [en] на сайте библиотеки.
Примеры идут вместе с исходниками. Их можно скачать следующей командой в консоли:
или же из исходников по прямой ссылке.
Документация представлена в форматах HTML и PDF.
Лицензия GNU LGPL.16 Answers 16
13 Answers 13
If you need a cross-platform solution, try Boost's Program Options library.
@Gollum, it sounds like Windows is a given dependency. Using the Program Options library means taking on another dependency. Sometimes that's not a big deal, sometimes it is.
He is trying to read an existing INI file, Using boost ist not an answer because it is using an INI like format.
You can use the Windows API functions, such as GetPrivateProfileString() and GetPrivateProfileInt().
They are obsolete because MS doesn't want you to use ini files any more, they are still ideal if you actually want to read or write such files.
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 requirementsIf you are already using Qt
Then read a value
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.
Not bad, although if you make changes they save them back to the .ini file without really telling you (i.e. the destructor calls sync() , which can be a surprise) and that destroys the comments and order in which variables were defined previously.
I use SimpleIni. It's cross-platform.
It appears to support Visual Studio and GCC, MIT license. As of the time of writing, its automated builds are failing, last release was in Sept. of 2013, last commit: June 2020
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.
It is very easy to read with simpleIni. Here is an example:
inih is a simple ini parser written in C, it comes with a C++ wrapper too. Example usage:
The author has also a list of existing libraries here.
Have you tried libconfig; very JSON-like syntax. I prefer it over XML configuration files.
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.
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.
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.
Читайте также: