c++ - सी++में आईएनआई फ़ाइल को पार्स करने का सबसे आसान तरीका क्या है?



winapi ini fileparse (11)

मैं सी ++ का उपयोग कर आईएनआई फाइल को पार्स करने की कोशिश कर रहा हूं। इस पर कोई सुझाव नहीं है कि इसे हासिल करने का सबसे अच्छा तरीका क्या है? क्या मुझे आईएनआई फाइल प्रोसेसिंग के लिए विंडोज एपीआई टूल्स का उपयोग करना चाहिए (जिसके साथ मैं पूरी तरह से अपरिचित हूं), ओपन-सोर्स सॉल्यूशन या इसे मैन्युअल रूप से पार्स करने का प्रयास?


Answers

यदि आपको क्रॉस-प्लेटफ़ॉर्म समाधान की आवश्यकता है, तो बूस्ट प्रोग्राम विकल्प लाइब्रेरी का प्रयास करें।


शायद देर से जवाब ... लेकिन, जानने के विकल्पों के लायक..यदि आपको एक क्रॉस-प्लेटफार्म समाधान की ज़रूरत है, तो निश्चित रूप से आप जीएलआईबी को आजमा सकते हैं, इसकी दिलचस्प .. ( https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html )


यदि आप पहले ही क्यूटी का उपयोग कर रहे हैं

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

फिर एक मूल्य पढ़ें

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

अन्य कनवर्टर का एक गुच्छा है जो आपके आईएनआई मानों को मानक प्रकारों और क्यूटी प्रकारों में परिवर्तित करता है। अधिक जानकारी के लिए QSettings पर क्यूटी दस्तावेज देखें।


inih सी में लिखा एक साधारण ini पार्सर है, यह भी एक सी ++ रैपर के साथ आता है। उदाहरण का उपयोग:

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

लेखक के पास मौजूदा पुस्तकालयों की एक सूची भी here


यह सवाल थोड़ा पुराना है, लेकिन मैं अपना जवाब पोस्ट करूंगा। मैंने विभिन्न आईएनआई कक्षाओं का परीक्षण किया है (आप उन्हें मेरी website पर देख सकते हैं) और मैं सरलइनी का भी उपयोग करता हूं क्योंकि मैं विंडोज़ और विनसी दोनों पर आईएनआई फाइलों के साथ काम करना चाहता हूं। विंडो का GetPrivateProfileString () केवल WinCE पर रजिस्ट्री के साथ काम करता है।

SimpleIni के साथ पढ़ना बहुत आसान है। यहाँ एक उदाहरण है:

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


मुझे पता है कि यह सवाल बहुत पुराना है, लेकिन मैं इस पर आया क्योंकि मुझे लिनक्स, win32 के लिए कुछ क्रॉस प्लेटफ़ॉर्म चाहिए ... मैंने नीचे दिया गया फ़ंक्शन लिखा है, यह एक ऐसा फ़ंक्शन है जो आईएनआई फाइलों को पार्स कर सकता है, उम्मीद है कि दूसरों को यह उपयोगी लगेगा।

नियम और चेतावनी: पार्स के लिए buf एक पूर्ण समाप्त स्ट्रिंग होना चाहिए। अपनी आईएनआई फ़ाइल को चार सरणी स्ट्रिंग में लोड करें और इस फ़ंक्शन को पार्स करने के लिए कॉल करें। सेक्शन नामों में उनके चारों ओर ब्रैकेट होना चाहिए, जैसे कि [माईसेक्शन], मूल्य भी और बिना किसी रिक्त स्थान के अनुभागों को लाइन पर शुरू होना चाहिए। यह Windows \ r \ n या Linux \ n लाइन समाप्ति के साथ फ़ाइलों को पार्स करेगा। टिप्पणियों को # या // का उपयोग करना चाहिए और फ़ाइल के शीर्ष पर शुरू होना चाहिए, आईएनआई प्रविष्टि डेटा के साथ कोई टिप्पणी मिश्रित नहीं की जानी चाहिए। उद्धरण और टिक वापसी रिटर्न के दोनों सिरों से छंटनी की जाती हैं। रिक्त स्थान केवल तभी छिड़के जाते हैं जब वे उद्धरण के बाहर हों। स्ट्रिंग्स को कोट्स रखने की आवश्यकता नहीं है, और उद्धरण गुम होने पर सफेद जगहों को छंटनी की जाती है। आप संख्याओं या अन्य डेटा को भी निकाल सकते हैं, उदाहरण के लिए यदि आपके पास फ्लोट है तो बस बफर पर एटॉफ (रेट) करें।

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

जब तक आप एप क्रॉस-प्लेटफॉर्म बनाने की योजना नहीं बनाते, विंडोज एपीआई कॉल का उपयोग करने का सबसे अच्छा तरीका होगा। केवल 16-बिट ऐप संगतता के लिए प्रदान किए जाने के बारे में API दस्तावेज़ में नोट को अनदेखा करें।


मैंने कभी भी आईएनआई फाइलों को पार्स नहीं किया है, इसलिए मैं इस मुद्दे पर बहुत विशिष्ट नहीं हो सकता।
लेकिन मेरे पास एक सलाह है:
जब तक कोई मौजूदा आपकी आवश्यकताओं को पूरा नहीं करता तब तक पहिया को पुन: पेश न करें

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

सौभाग्य :)


यदि आप प्लेटफार्म पोर्टेबिलिटी में रूचि रखते हैं, तो आप Boost.PropertyTree को भी आजमा सकते हैं। यह ini को दृढ़ता प्रारूप के रूप में समर्थन करता है, हालांकि संपत्ति का पेड़ केवल 1 स्तर गहरा होना चाहिए।


सबसे पहले, आपको एक भाषा वकील की तरह सोचना सीखना है।

सी ++ विनिर्देश किसी विशेष कंपाइलर, ऑपरेटिंग सिस्टम या सीपीयू का संदर्भ नहीं देता है। यह एक सार मशीन का संदर्भ देता है जो वास्तविक प्रणालियों का एक सामान्यीकरण है। भाषा वकील की दुनिया में, प्रोग्रामर का काम सार मशीन के लिए कोड लिखना है; कंपाइलर का काम उस कोड को कंक्रीट मशीन पर वास्तविक बनाना है। Specidly specidly कोडिंग करके, आप निश्चित हो सकते हैं कि आपका कोड किसी भी सिस्टम पर एक अनुपालन C ++ कंपाइलर के साथ संकलन के बिना संकलित और चलाएगा, चाहे आज या 50 साल से हो।

सी ++ 98 / सी ++ 03 विनिर्देश में सार मशीन मूल रूप से सिंगल-थ्रेडेड है। तो बहु-थ्रेडेड सी ++ कोड लिखना संभव नहीं है जो spec के संबंध में "पूरी तरह से पोर्टेबल" है। यह कल्पना मेमोरी लोड और स्टोर्स की परमाणुता के बारे में कुछ भी नहीं कहती है या जिस क्रम में लोड और स्टोर हो सकते हैं, म्यूटेक्स जैसी चीज़ों को कभी भी ध्यान न दें।

बेशक, आप विशेष कंक्रीट सिस्टम के लिए अभ्यास में बहु थ्रेडेड कोड लिख सकते हैं - जैसे कि पेंथ्रेड या विंडोज। लेकिन सी ++ 98 / सी ++ 03 के लिए बहु थ्रेडेड कोड लिखने का कोई मानक तरीका नहीं है।

सी ++ 11 में सार मशीन डिज़ाइन द्वारा बहु-थ्रेडेड है। इसमें एक अच्छी तरह से परिभाषित स्मृति मॉडल भी है ; यानी, यह कहता है कि स्मृति तक पहुंचने की बात आने पर संकलक क्या कर सकता है और नहीं कर सकता है।

निम्नलिखित उदाहरण पर विचार करें, जहां वैश्विक चर की एक जोड़ी दो धागे द्वारा समवर्ती रूप से उपयोग की जाती है:

           Global
           int x, y;

Thread 1            Thread 2
x = 17;             cout << y << " ";
y = 37;             cout << x << endl;

थ्रेड 2 आउटपुट क्या हो सकता है?

सी ++ 98 / सी ++ 03 के तहत, यह अपरिभाषित व्यवहार भी नहीं है; सवाल स्वयं व्यर्थ है क्योंकि मानक "थ्रेड" नामक किसी भी चीज पर विचार नहीं करता है।

सी ++ 11 के तहत, परिणाम अपरिभाषित व्यवहार है, क्योंकि लोड और स्टोर सामान्य रूप से परमाणु नहीं होना चाहिए। जो अधिक सुधार की तरह प्रतीत नहीं हो सकता है ... और स्वयं ही, यह नहीं है।

लेकिन सी ++ 11 के साथ, आप इसे लिख सकते हैं:

           Global
           atomic<int> x, y;

Thread 1                 Thread 2
x.store(17);             cout << y.load() << " ";
y.store(37);             cout << x.load() << endl;

अब चीजें ज्यादा दिलचस्प हो जाती हैं। सबसे पहले, यहां व्यवहार परिभाषित किया गया है । थ्रेड 2 अब 0 0 प्रिंट कर सकता है (यदि यह थ्रेड 1 से पहले चलता है), 37 17 (यदि यह थ्रेड 1 के बाद चलता है), या 0 17 (यदि यह थ्रेड 1 के बाद चलता है तो एक्स को असाइन करता है लेकिन इससे पहले कि यह वाई को असाइन करता है)।

यह मुद्रित नहीं कर सकता है 37 0 , क्योंकि सी ++ 11 में परमाणु भार / स्टोर के लिए डिफ़ॉल्ट मोड अनुक्रमिक स्थिरता को लागू करना है । इसका मतलब यह है कि सभी लोड और स्टोर्स "जैसे" हो सकते हैं, जैसा कि आपने उन्हें प्रत्येक थ्रेड के भीतर लिखा था, जबकि धागे के बीच संचालन को अंतःस्थापित किया जा सकता है, हालांकि सिस्टम पसंद करता है। तो परमाणुओं का डिफ़ॉल्ट व्यवहार भार और दुकानों के लिए परमाणुता और व्यवस्था दोनों प्रदान करता है।

अब, एक आधुनिक सीपीयू पर, अनुक्रमिक स्थिरता सुनिश्चित करना महंगा हो सकता है। विशेष रूप से, कंपाइलर यहां हर पहुंच के बीच पूर्ण उड़ा स्मृति बाधाओं को उत्सर्जित करने की संभावना है। लेकिन अगर आपका एल्गोरिदम आउट-ऑफ-ऑर्डर लोड और स्टोर बर्दाश्त कर सकता है; यानी, अगर इसे परमाणु की आवश्यकता है लेकिन आदेश नहीं दे रहा है; यानी, यदि यह इस कार्यक्रम से आउटपुट के रूप में 37 0 सहन कर सकता है, तो आप इसे लिख सकते हैं:

           Global
           atomic<int> x, y;

Thread 1                            Thread 2
x.store(17,memory_order_relaxed);   cout << y.load(memory_order_relaxed) << " ";
y.store(37,memory_order_relaxed);   cout << x.load(memory_order_relaxed) << endl;

सीपीयू जितना आधुनिक होगा, उतना ही अधिक संभावना है कि यह पिछले उदाहरण की तुलना में तेज़ हो।

अंत में, अगर आपको केवल विशेष भार और स्टोर रखने की आवश्यकता है, तो आप लिख सकते हैं:

           Global
           atomic<int> x, y;

Thread 1                            Thread 2
x.store(17,memory_order_release);   cout << y.load(memory_order_acquire) << " ";
y.store(37,memory_order_release);   cout << x.load(memory_order_acquire) << endl;

यह हमें आदेशित लोड और स्टोर्स पर वापस ले जाता है - इसलिए 37 0 अब संभव आउटपुट नहीं है - लेकिन यह न्यूनतम ओवरहेड के साथ ऐसा करता है। (इस छोटे उदाहरण में, परिणाम पूर्ण उड़ा अनुक्रमिक स्थिरता के समान है; एक बड़े कार्यक्रम में, यह नहीं होगा।)

बेशक, यदि आप केवल एक ही आउटपुट देखना चाहते हैं तो 0 0 या 37 17 , तो आप मूल कोड के आस-पास एक म्यूटेक्स लपेट सकते हैं। लेकिन अगर आपने इसे अभी तक पढ़ा है, तो मैं शर्त लगाता हूं कि आप पहले ही जानते हैं कि यह कैसे काम करता है, और यह उत्तर मेरे इरादे से पहले से ही लंबा है :-)।

तो, नीचे की रेखा। म्यूटेक्स महान हैं, और सी ++ 11 उन्हें मानकीकृत करता है। लेकिन कभी-कभी प्रदर्शन कारणों से आप निचले स्तर के प्राइमेटिव (उदाहरण के लिए, क्लासिक डबल-चेक लॉकिंग पैटर्न ) चाहते हैं। नया मानक म्यूटेक्स और हालत चर जैसे उच्च स्तरीय गैजेट प्रदान करता है, और यह परमाणु प्रकारों और मेमोरी बाधा के विभिन्न स्वाद जैसे निम्न-स्तरीय गैजेट भी प्रदान करता है। तो अब आप मानक द्वारा निर्दिष्ट भाषा के भीतर पूरी तरह से परिष्कृत, उच्च-प्रदर्शन समवर्ती दिनचर्या लिख ​​सकते हैं, और आप निश्चित हो सकते हैं कि आपका कोड संकलित हो जाएगा और आज के सिस्टम और कल दोनों पर अपरिवर्तित होगा।

हालांकि फ्रैंक होने के बावजूद, जब तक कि आप एक विशेषज्ञ न हों और कुछ गंभीर निम्न-स्तरीय कोड पर काम न करें, आपको शायद म्यूटेक्स और हालत चर के साथ रहना चाहिए। यही वह है जो मैं करना चाहता हूं।

इस सामान पर अधिक जानकारी के लिए, इस ब्लॉग पोस्ट को देखें।





c++ winapi ini fileparse