วิธีที่ง่ายที่สุดในการแยกวิเคราะห์ไฟล์ INI ใน C ++ คืออะไร?


89

ฉันพยายามแยกวิเคราะห์ไฟล์ INI โดยใช้ C ++ เคล็ดลับใด ๆ เกี่ยวกับวิธีที่ดีที่สุดในการบรรลุเป้าหมายนี้ ฉันควรใช้เครื่องมือ Windows API สำหรับการประมวลผลไฟล์ INI (ซึ่งฉันไม่คุ้นเคยโดยสิ้นเชิง) โซลูชันโอเพ่นซอร์สหรือพยายามแยกวิเคราะห์ด้วยตนเอง

คำตอบ:


112

คุณสามารถใช้ฟังก์ชั่นของ Windows API เช่นGetPrivateProfileString ()และGetPrivateProfileInt ()


4
ไม่แนะนำให้ใช้ GetPrivateProfileInt () และฟังก์ชันอื่น ๆ โดย MSDN เนื่องจากเป็นฟังก์ชันที่ล้าสมัยและยังคงมีให้เฉพาะสำหรับความเข้ากันได้ของ baskward กับระบบ 16 บิตรุ่นเก่าเท่านั้น แทนที่จะใช้วิธีการอื่น msdn.microsoft.com/en-us/library/windows/desktop/…
Zdeno Pavlik

พวกเขาล้าสมัยเนื่องจาก MS ไม่ต้องการให้คุณใช้ไฟล์ ini อีกต่อไปพวกเขายังคงเหมาะอย่างยิ่งหากคุณต้องการอ่านหรือเขียนไฟล์ดังกล่าวจริงๆ
นีล

114

หากคุณต้องการโซลูชันข้ามแพลตฟอร์มให้ลองใช้ไลบรารีตัวเลือกโปรแกรมของ Boost


1
ฉันขอแนะนำห้องสมุดนี้ด้วย
varnie

22
นี่คือวิธีที่จะไปฉันไม่เข้าใจว่าทำไมผู้คนถึงโหวตคำตอบที่ไม่ธรรมดา
Ramadheer Singh

18
@Gollum ดูเหมือนว่า Windows จะเป็นการพึ่งพาที่กำหนด การใช้ไลบรารีตัวเลือกโปรแกรมหมายถึงการพึ่งพาอื่น บางครั้งนั่นไม่ใช่เรื่องใหญ่บางครั้งก็เป็นเช่นนั้น
IJ Kennedy

5
@malat ฉันสับสนฉันไม่ได้พูดถึงการลงคะแนน?
sjdowling

2
เขากำลังพยายามอ่านไฟล์ INI ที่มีอยู่การใช้ boost ไม่ใช่คำตอบเพราะใช้รูปแบบ INI like
Lothar

22

ฉันไม่เคยแยกวิเคราะห์ไฟล์ 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

โชคดี :)


16

หากคุณใช้ Qt

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

จากนั้นอ่านค่า

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

มีตัวแปลงอื่น ๆ อีกมากมายที่แปลงค่า INI ของคุณเป็นทั้งประเภทมาตรฐานและประเภท Qt ดูเอกสาร Qt เกี่ยวกับ QSettings สำหรับข้อมูลเพิ่มเติม


ไม่เลวแม้ว่าคุณจะทำการเปลี่ยนแปลงพวกเขาจะบันทึกกลับเป็นไฟล์. ini โดยไม่ได้บอกคุณจริงๆ (เช่นการเรียกตัวทำลายsync()ซึ่งอาจทำให้ประหลาดใจ) และนั่นทำลายความคิดเห็นและลำดับที่ตัวแปรที่กำหนดไว้ก่อนหน้านี้ ...
Alexis Wilke


8

คำถามนี้เก่าไปหน่อย แต่ฉันจะโพสต์คำตอบ ฉันได้ทดสอบคลาส 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);

6

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

ผู้เขียนยังมีรายชื่อของห้องสมุดที่มีอยู่ที่นี่



3

หากคุณสนใจในการพกพาแพลตฟอร์มคุณสามารถลอง Boost.PropertyTree สนับสนุน ini เป็นรูปแบบการคงอยู่แม้ว่าโครงสร้างคุณสมบัติของฉันจะเป็นระดับลึก 1 เท่านั้น


2

หากคุณไม่ได้วางแผนที่จะสร้างแอปข้ามแพลตฟอร์มการใช้การเรียก Windows API จะเป็นวิธีที่ดีที่สุด อย่าสนใจหมายเหตุในเอกสาร API เกี่ยวกับการให้บริการเฉพาะสำหรับความเข้ากันได้ของแอป 16 บิตเท่านั้น


1

อาจจะเป็นคำตอบที่ล่าช้า .. แต่ก็ควรรู้ว่ามีทางเลือกอะไรบ้าง .. หากคุณต้องการโซลูชันข้ามแพลตฟอร์มคุณสามารถลอง GLIB ได้แน่นอนมันน่าสนใจ .. ( https://developer.gnome.org/glib/stable/glib- คีย์ - ค่า - ไฟล์ -parser.html )


0

ฉันรู้ว่าคำถามนี้เก่ามาก แต่ฉันมาถึงมันเพราะฉันต้องการบางอย่างข้ามแพลตฟอร์มสำหรับ linux, win32 ... ฉันเขียนฟังก์ชันด้านล่างมันเป็นฟังก์ชั่นเดียวที่สามารถแยกวิเคราะห์ไฟล์ INI หวังว่าคนอื่นจะพบว่ามีประโยชน์

กฎและข้อควรระวัง: buf ที่จะแยกวิเคราะห์ต้องเป็นสตริงที่สิ้นสุดด้วย NULL โหลดไฟล์ ini ของคุณลงในสตริงอาร์เรย์ char และเรียกใช้ฟังก์ชันนี้เพื่อแยกวิเคราะห์ ชื่อส่วนต้องมีเครื่องหมายวงเล็บ [] ล้อมรอบเช่น [MySection] นี้ค่าและส่วนต่างๆต้องขึ้นต้นในบรรทัดโดยไม่มีช่องว่างนำหน้า มันจะแยกวิเคราะห์ไฟล์ด้วย Windows \ r \ n หรือด้วยปลายบรรทัดของ Linux \ n ข้อคิดเห็นควรใช้ # หรือ // และขึ้นต้นที่ด้านบนของไฟล์ไม่ควรผสมความคิดเห็นกับข้อมูลเข้า INI เครื่องหมายคำพูดและขีดถูกตัดออกจากปลายทั้งสองด้านของสตริงส่งคืน ช่องว่างจะถูกตัดแต่งหากอยู่นอกเครื่องหมายคำพูดเท่านั้น สตริงไม่จำเป็นต้องมีเครื่องหมายคำพูดและช่องว่างจะถูกตัดออกหากไม่มีเครื่องหมายคำพูด คุณยังสามารถแยกตัวเลขหรือข้อมูลอื่น ๆ ได้เช่นถ้าคุณมี float เพียงแค่ทำ atof (ret) บน ret buffer

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

0

ฉันลงเอยด้วยการใช้ inipp ซึ่งไม่ได้กล่าวถึงในหัวข้อนี้

https://github.com/mcmtroffaes/inipp

เป็นส่วนหัวที่ได้รับอนุญาตของ MIT เท่านั้นซึ่งง่ายพอที่จะเพิ่มลงในโครงการและ 4 บรรทัดเพื่อใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.