INI Dosyasını C ++ 'da çözümlemenin en kolay yolu nedir?


89

C ++ kullanarak bir INI dosyasını ayrıştırmaya çalışıyorum. Bunu başarmanın en iyi yolunun ne olduğuna dair herhangi bir ipucu var mı? INI dosya işleme (tamamen aşina olmadığım) için Windows API araçlarını, açık kaynaklı bir çözümü kullanmalı mıyım yoksa manuel olarak ayrıştırmaya mı çalışmalıyım?

Yanıtlar:


112

GetPrivateProfileString () ve GetPrivateProfileInt () gibi Windows API işlevlerini kullanabilirsiniz .


4
GetPrivateProfileInt () ve diğer işlevler, eski olduklarından ve yalnızca daha eski, 16 bit sistemlerle baştan başa uyumluluk için sağlandığından, MSDN tarafından önerilmemektedir. Bunun yerine başka bir yaklaşım kullanın. msdn.microsoft.com/en-us/library/windows/desktop/…
Zdeno Pavlik

MS artık ini dosyalarını kullanmanızı istemediği için kullanılmamaktadır, bu tür dosyaları gerçekten okumak veya yazmak istiyorsanız, yine de idealdirler.
Neil

114

Çapraz platform çözüme ihtiyacınız varsa, Boost'un Program Seçenekleri kitaplığını deneyin .


1
bu kütüphaneyi de tavsiye
ederim

22
gidilecek yol bu, insanların neden o kadar genel olmayan yanıta oy verdiklerini anlamıyorum.
Ramadheer Singh

18
@Gollum, Windows belirli bir bağımlılık gibi görünüyor. Program Seçenekleri kütüphanesini kullanmak, başka bir bağımlılık üstlenmek demektir. Bazen bu çok önemli değil, bazen öyle.
IJ Kennedy

5
@malat Kafam karıştı, olumsuz oy kullanmaktan bahsetmedim?
sjdowling

2
Mevcut bir INI dosyasını okumaya çalışıyor, INI benzeri bir format kullandığı için boost kullanmak bir cevap değil.
Lothar


16

Zaten Qt kullanıyorsanız

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

Sonra bir değer okuyun

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

INI değerlerinizi hem standart tiplere hem de Qt tiplerine dönüştüren bir sürü başka dönüştürücü vardır. Daha fazla bilgi için QSettings'deki Qt belgelerine bakın.


Fena değil, ancak değişiklikler yaparsanız, onları gerçekten size söylemeden (yani yıkıcı çağrıları sync(), bu bir sürpriz olabilir) .ini dosyasına geri kaydederler ve bu, değişkenlerin önceden tanımlandığı yorumları ve sıralamayı yok eder ...
Alexis Wilke


8

bu soru biraz eski, ancak cevabımı göndereceğim. Çeşitli INI sınıflarını test ettim (bunları web sitemde görebilirsiniz ) ve ayrıca simpleIni'yi kullanıyorum çünkü hem Windows hem de winCE'de INI dosyalarıyla çalışmak istiyorum. Pencerenin GetPrivateProfileString () yalnızca winCE üzerindeki kayıt defteri ile çalışır.

SimpleIni ile okumak çok kolay. İşte bir örnek:

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

6

inih , C ile yazılmış basit bir ini ayrıştırıcısıdır, ayrıca bir C ++ sarıcı ile birlikte gelir. Örnek kullanım:

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

Yazar ayrıca burada mevcut kitaplıkların bir listesine sahiptir .



3

Platform taşınabilirliği ile ilgileniyorsanız, Boost.PropertyTree'yi de deneyebilirsiniz. Kalıcılık biçimi olarak ini'yi destekler, ancak özellik ağacı yalnızca 1 düzey derinliğinde olabilir.


2

Uygulamayı çapraz platform oluşturmayı planlamıyorsanız, Windows API çağrılarını kullanmak en iyi yol olacaktır. Yalnızca 16 bit uygulama uyumluluğu için sağlanmayla ilgili API belgelerindeki notu dikkate almayın.



0

Bu sorunun çok eski olduğunu biliyorum ama üzerine geldim çünkü linux için çapraz platform, win32 için bir şeye ihtiyacım vardı ... Aşağıdaki işlevi yazdım, INI dosyalarını ayrıştırabilen tek bir işlev, umarım diğerleri onu yararlı bulacaktır.

kurallar ve uyarılar: ayrıştırılacak tampon, NULL ile sonlandırılmış bir dize olmalıdır. İni dosyanızı bir char dizisi dizesine yükleyin ve ayrıştırmak için bu işlevi çağırın. Bölüm adlarının etrafında [] köşeli parantez olmalıdır, örneğin bu [MySection], ayrıca değerler ve bölümler, başında boşluklar olmadan bir satırda başlamalıdır. Dosyaları Windows \ r \ n veya Linux \ n satır sonlarıyla ayrıştırır. Yorumlar # veya // kullanmalı ve dosyanın en üstünde başlamalı, INI girdi verileriyle hiçbir yorum karıştırılmamalıdır. Alıntılar ve işaretler, dönüş dizesinin her iki ucundan da kırpılır. Boşluklar yalnızca teklifin dışındaysa kırpılır. Dizelerin tırnak işareti olması gerekmez ve tırnak işaretleri eksikse beyaz boşluklar kırpılır. Numaraları veya diğer verileri de ayıklayabilirsiniz, örneğin bir kayan nokta varsa, yalnızca ret tamponunda bir atof (ret) gerçekleştirin.

//  -----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
}

Nasıl kullanılır ... örnek ....

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
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.