超級好用的配置文件解析器:minIni
哈嘍,我是老吳。這兩天發(fā)現(xiàn)一個還不錯的開源項(xiàng)目,記錄一下學(xué)習(xí)心得。
對于嵌入式開發(fā),INI 文件使用門檻低、用途廣,掌握一個穩(wěn)定的開源 INI 解析器可以提升編碼效率、避免重復(fù)造輪子。
另外,對于一個 C 初學(xué)者,MinIni 代碼嚴(yán)謹(jǐn)且健壯,API設(shè)計(jì)合理,是一個非常適合用來練習(xí)文本讀寫、字符串操作的開源項(xiàng)目。
minIni 是什么?
https://github.com/compuphase/minIni
minIni 是一個用于讀取和寫入 INI 文件的庫。
什么是 INI 文件?
INI 是一種有簡單語法的純文本文件,例如:
[Network]
hostname=My Computer
address=dhcp
dns=192.168.1.1
timeout=10
[Network] 是一個 Section,Section 下面有多個鍵值對。
INI 文件的特點(diǎn)是簡單易用、可讀性好。
Linux 系統(tǒng) etc 目錄下的許多配置文件都是 INI 文件,只是有的配置文件沒有顯式聲明 Section。
例如 bluez 的配置文件 /etc/bluetooth/main.conf:
[General]
# Default adaper name
Name = BlueZ
[Policy]
# AutoEnable defines option to enable all controllers when they are found.
AutoEnable=true
minIni 的幾個特點(diǎn):
1> minIni 大約是 950 行代碼 (包括注釋),是一個真正的 “迷你” INI 文件解析器,非常容易移植到各種嵌入式平臺。
2> minIni 不需要標(biāo)準(zhǔn) C/C++ 庫中的 文件 I/O 函數(shù),且允許通過宏配置要選擇文件 I/O 接口。
3> minIni 僅使用 stack ,完全不使用動態(tài)內(nèi)存(malloc)。
4> 有 C++ binding, 能很好地配合 C++ 使用。
minIni 怎么用?
minIni 的核心源碼就一個 .c 和 .h 文件,我們直接將它們集成到項(xiàng)目代碼里即可。
快速地了解它的 API:
#include?"minIni.h"
#define?sizearray(a)??(sizeof(a)?/?sizeof((a)[0]))
const?char?inifile[]?=?"example.ini";
int?main(void)
{
????char?str[100];
????char?section[50];
????long?n;
????n?=?ini_gets("Network",?"address",?"dummy",?str,?sizearray(str),?inifile);
????if?(n?>=?0)?printf("Network/address=%s",?str);
????n?=?ini_getl("Network",?"timeout",?-1,?inifile);
????printf("Network/timeout=%ld\n",?n);
待解析的文件內(nèi)容:
[Network]
hostname=My Computer
address=dhcp
dns=192.168.1.1
timeout=10
運(yùn)行結(jié)果:
Network/address=dhcp
Network/timeout=10
ini_gets() 用于獲取字符串類型的值。
參數(shù) 1 是 Section name;
參數(shù) 2 是 Key name;
參數(shù) 3 是獲取不到值時的默認(rèn)值;
參數(shù) 4 是用于保存目標(biāo)鍵值的 Buffer;
參數(shù) 5 是 Buffer 的長度;
參數(shù) 6 是 INI 文件的路徑;
ini_getl() 用于獲取整型類型的值,參數(shù)的含義和 ini_gets() 大同小異。
完整的 API 列表:

minIni 的內(nèi)部實(shí)現(xiàn)?
我簡單地瀏覽過 minIni 的實(shí)現(xiàn)代碼,感覺良好。
想實(shí)現(xiàn)解析 INI 文件的功能并不難,難的是要認(rèn)真考慮各種邊界情況和異常情況,保證程序的健壯性和 API 的合理性。
以 ini_gets() 為例:

就是先打開文件,然后用 getkeystring() 找到目標(biāo)鍵值,最后拷貝給調(diào)用者。
getkeystring() 負(fù)責(zé)真正地解析文本:
大約有 80 行代碼,我簡單地總結(jié)一下思路:
1> 用 fgets 進(jìn)行逐行讀取,用 strrchr 找到包含 '[' 和 ']' 的行,然后再用 strncasecmp 找到目標(biāo) Secntion 所在的行。
2> 繼續(xù)用 fgets 進(jìn)行逐行讀取,用 strrchr 找到包含 '=' 的行,然后再用 strncasecmp 找到目標(biāo) Key 所在的行。
3> 用 strncpy 將目標(biāo) Key 的值拷貝給調(diào)用者。
雖然解析文本只需要做到這 3 個步驟,但是由于需要對各種邊界情況進(jìn)行判斷,以及處理空格之類的無效字符,所以需要細(xì)心且反復(fù)調(diào)試才能編寫好這個函數(shù)。
總結(jié)
對于嵌入式開發(fā),INI 文件使用門檻低、用途廣,掌握一個穩(wěn)定的開源 INI 解析器可以提升編碼效率、避免重復(fù)造輪子。
對于一個 C 初學(xué)者,MinIni 代碼嚴(yán)謹(jǐn)且健壯,API設(shè)計(jì)合理,是一個非常適合用來練習(xí)文本讀寫、字符串操作的開源項(xiàng)目,值得一看。
其他 INI 解析的開源項(xiàng)目:
https://github.com/rxi/ini
https://github.com/benhoyt/inih
