Apa cara termudah untuk mengurai File INI di C ++?

89

Saya mencoba mengurai file INI menggunakan C ++. Adakah tip tentang cara terbaik untuk mencapai ini? Haruskah saya menggunakan alat Windows API untuk pemrosesan file INI (yang sama sekali tidak saya kenal), solusi open-source atau mencoba menguraikannya secara manual?

conmulligan
sumber

Jawaban:

112

Anda dapat menggunakan fungsi Windows API, seperti GetPrivateProfileString () dan GetPrivateProfileInt () .

Joel Spolsky
sumber
4
GetPrivateProfileInt () dan fungsi lainnya tidak direkomendasikan oleh MSDN, karena sudah usang dan masih tersedia hanya untuk kompatibilitas baskward dengan sistem 16-bit yang lebih lama. Daripada itu gunakan pendekatan lain. msdn.microsoft.com/en-us/library/windows/desktop/…
Zdeno Pavlik
Mereka sudah usang karena MS tidak ingin Anda menggunakan file ini lagi, mereka masih ideal jika Anda benar-benar ingin membaca atau menulis file semacam itu.
Neil
114

Jika Anda memerlukan solusi lintas platform, coba pustaka Opsi Program Boost .

Adam Mitz
sumber
1
saya akan menyarankan perpustakaan ini juga
varnie
22
ini adalah cara untuk pergi, saya tidak mengerti mengapa orang hanya memilih jawaban yang tidak terlalu umum.
Ramadheer Singh
17
@ Gollum, sepertinya Windows adalah ketergantungan tertentu. Menggunakan pustaka Opsi Program berarti mengambil ketergantungan lain. Terkadang itu bukan masalah besar, terkadang memang begitu.
IJ Kennedy
5
@malat Saya bingung, saya tidak menyebutkan downvoting?
sjdowling
2
Dia mencoba membaca file INI yang ada, Menggunakan boost ist bukan jawaban karena menggunakan format seperti INI.
Lothar
16

Jika Anda sudah menggunakan Qt

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

Kemudian bacalah nilainya

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

Ada banyak konverter lain yang mengubah nilai INI Anda menjadi tipe standar dan tipe Qt. Lihat dokumentasi Qt pada QSettings untuk informasi lebih lanjut.

Dat Chu
sumber
Tidak buruk, meskipun jika Anda membuat perubahan, mereka menyimpannya kembali ke file .ini tanpa benar-benar memberi tahu Anda (yaitu panggilan destruktor sync(), yang bisa menjadi kejutan) dan itu menghancurkan komentar dan urutan variabel yang didefinisikan sebelumnya ...
Alexis Wilke
16

Saya menggunakan SimpleIni . Ini lintas platform.

Harold Ekstrom
sumber
SimpleIni sekarang dihosting di Github.
Richard Ye
8

pertanyaan ini agak tua, tapi saya akan memposting jawaban saya. Saya telah menguji berbagai kelas INI (Anda dapat melihatnya di situs web saya ) dan saya juga menggunakan simpleIni karena saya ingin bekerja dengan file INI di windows dan winCE. GetPrivateProfileString () Window hanya berfungsi dengan registri di winCE.

Sangat mudah dibaca dengan simpleIni. Berikut ini contohnya:

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

inih adalah parser ini sederhana yang ditulis dalam C, dilengkapi dengan pembungkus C ++ juga. Contoh penggunaan:

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

Penulis juga memiliki daftar pustaka yang ada di sini .

nimcap
sumber
4

Sudahkah Anda mencoba libconfig ; sangat mirip dengan sintaks JSON. Saya lebih suka daripada file konfigurasi XML.

Christopher Lightfoot
sumber
3

Jika Anda tertarik dengan portabilitas platform, Anda juga dapat mencoba Boost.PropertyTree. Ini mendukung ini sebagai format persistensi, meskipun pohon properti saya hanya sedalam 1 tingkat.

gast128
sumber
2

Kecuali Anda berencana membuat aplikasi lintas platform, menggunakan panggilan Windows API akan menjadi cara terbaik untuk melakukannya. Abaikan saja catatan dalam dokumentasi API tentang hanya disediakan untuk kompatibilitas aplikasi 16-bit.

crashmstr
sumber
0

Saya tahu pertanyaan ini sangat tua, tetapi saya mendapatkannya karena saya membutuhkan sesuatu lintas platform untuk linux, win32 ... Saya menulis fungsi di bawah ini, ini adalah fungsi tunggal yang dapat mengurai file INI, semoga orang lain akan menganggapnya berguna.

rules & caveats: buf to parse harus berupa string yang diakhiri NULL. Muat file ini Anda ke dalam string array karakter dan panggil fungsi ini untuk menguraikannya. nama bagian harus memiliki tanda kurung [] di sekelilingnya, seperti [MySection] ini, juga nilai dan bagian harus dimulai pada baris tanpa spasi. Ini akan mengurai file dengan Windows \ r \ n atau dengan Linux \ n akhiran baris. Komentar harus menggunakan # atau // dan dimulai dari bagian atas file, tidak ada komentar yang dicampur dengan data entri INI. Kutipan dan centang dipangkas dari kedua ujung string kembali. Spasi hanya dipangkas jika berada di luar kutipan. String tidak harus memiliki tanda kutip, dan spasi kosong dipangkas jika tanda kutip tidak ada. Anda juga dapat mengekstrak angka atau data lain, misalnya jika Anda memiliki float, lakukan saja atof (ret) pada buffer 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
}

Cara menggunakan ... contoh ....

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
}
12oclocker
sumber
0

Saya akhirnya menggunakan inipp yang tidak disebutkan di utas ini.

https://github.com/mcmtroffaes/inipp

Apakah hanya implementasi header berlisensi MIT yang cukup sederhana untuk ditambahkan ke proyek dan 4 baris untuk digunakan.

pengguna1867382
sumber