2011-05-30 17 views
57

साथ INI फ़ाइल पार्स करने के लिए कैसे मैं जो की तरह कुछ नमूना मान हैं एक INI फ़ाइल है: मैं इन मूल्यों को लोड और उन्हें बूस्ट के साथ अपने आवेदन में मुद्रित करने के लिए कोशिश कर रहा हूँबूस्ट

[Section1] 
Value1 = 10 
Value2 = a_text_string 

लेकिन मुझे नहीं पता समझें कि सी ++ में ऐसा कैसे करें।

मैंने कुछ उदाहरण खोजने के लिए इस मंच में खोज की है (मैं हमेशा सी का उपयोग करता हूं और इसलिए मैं सी ++ में बहुत अच्छा नहीं हूं) लेकिन मुझे केवल फाइलों से मूल्यों को पढ़ने के तरीके के बारे में केवल उदाहरण मिलते हैं।

मुझे string = Section1.Value2 की तरह, मुझे केवल एक ही मूल्य लोड करने की आवश्यकता है क्योंकि मुझे सभी मानों को पढ़ने की आवश्यकता नहीं है, लेकिन उनमें से कुछ ही हैं।

मैं एकल मान लोड करना चाहता हूं और उन्हें अपने आवेदन में इच्छित होने पर उन्हें उपयोग करने के लिए चर में स्टोर करना चाहता हूं।

बूस्ट के साथ ऐसा करना संभव है?

पल में, मैं इस कोड का उपयोग कर रहा हूँ:

#include <iostream> 
#include <string> 
#include <set> 
#include <sstream> 
#include <exception> 
#include <fstream> 
#include <boost/config.hpp> 
#include <boost/program_options/detail/config_file.hpp> 
#include <boost/program_options/parsers.hpp> 

namespace pod = boost::program_options::detail; 

int main() 
{ 
    std::ifstream s("file.ini"); 
    if(!s) 
    { 
     std::cerr<<"error"<<std::endl; 
     return 1; 
    } 

    std::set<std::string> options; 
    options.insert("Test.a"); 
    options.insert("Test.b"); 
    options.insert("Test.c"); 

    for (boost::program_options::detail::config_file_iterator i(s, options), e ; i != e; ++i) 
     std::cout << i->value[0] << std::endl; 
    } 

लेकिन यह सिर्फ एक for पाश में सभी मूल्यों को पढ़ने; इसके विपरीत मैं केवल वही मान पढ़ना चाहता हूं जब मैं चाहता हूं और मुझे फ़ाइल में मान डालने की आवश्यकता नहीं है, क्योंकि यह मेरे प्रोग्राम में आवश्यक सभी मानों के साथ पहले ही लिखा गया है।

उत्तर

122

तुम भी .ini फ़ाइलों को पढ़ने में Boost.PropertyTree उपयोग कर सकते हैं: उनके सरल संरचना की वजह से

#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/ini_parser.hpp> 

... 

boost::property_tree::ptree pt; 
boost::property_tree::ini_parser::read_ini("config.ini", pt); 
std::cout << pt.get<std::string>("Section1.Value1") << std::endl; 
std::cout << pt.get<std::string>("Section1.Value2") << std::endl; 
+0

शानदार उत्तर! मुझे अपने आवेदन के लिए यही चाहिए। वास्तव में बहुत बहुत धन्यवाद! –

+0

क्या होगा यदि मुझे उपलब्ध कुंजी के कुछ सेट नहीं पता हैं, लेकिन मैं अभी भी कुंजी = मूल्य जोड़े की पूरी सूची प्राप्त करना चाहता हूं? अर्थात। "section1.Value1" और "section1.Value2" स्थिरांक का उपयोग किए बिना आप अपने प्रोग्राम को फिर से लिखेंगे? – javapowered

+0

अपडेट: मुझे यह प्रश्न मिला है http://stackoverflow.com/questions/11065938/boost-program-options-get-all-entries-in-section इसके अनुसार कस्टम कोड लिखने के बिना संभव नहीं है ... – javapowered

1

फ़ाइल को पार्स करने की आवश्यकता है, जिसे अनुक्रमिक रूप से किया जाना है। इसलिए मैं पूरी फाइल को पढ़ूंगा, कुछ संग्रहों में सभी मानों को संग्रहीत करूंगा (map या unordered_map, शायद या तो pair<section, key> का उपयोग कुंजी के रूप में या नक्शे के मानचित्र का उपयोग करके) और आवश्यकता होने पर उन्हें वहां से लाएं।

3

पार्सिंग INI फ़ाइलों आसान है। कुल्हाड़ी मैं कुछ पंक्तियों में लिख सकते का उपयोग वर्गों, गुण और टिप्पणियों पार्स करने के लिए: पूरे फ़ाइल को पढ़ने नहीं के बारे में

auto trailing_spaces = *space & endl; 
auto section = '[' & r_alnumstr() & ']'; 
auto name = +(r_any() - '=' - endl - space); 
auto value = '"' & *("\\\"" | r_any() - '"') & '"' 
    | *(r_any() - trailing_spaces); 
auto property = *space & name & *space & '=' & *space 
    & value & trailing_spaces; 
auto comment = ';' & *(r_any() - endl) & endl; 
auto ini_file = *comment & *(section & *(prop_line | comment)) & r_end(); 

अधिक विस्तृत उदाहरण Reference.pdf

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

अंत में, मुझे यकीन नहीं है कि पूरी फाइल पढ़ने से बचने से कोई फायदा होता है। आईएनआई फाइलें आम तौर पर बहुत छोटी होती हैं, और चूंकि हार्ड ड्राइव और एकाधिक बफरिंग सिस्टम एक या एक से अधिक क्षेत्रों को पढ़ते हैं (भले ही आपको केवल एक बाइट की आवश्यकता हो), इसलिए मुझे संदेह है कि फ़ाइल को आंशिक रूप से पढ़ने की कोशिश करके कोई प्रदर्शन सुधार होगा (विशेष रूप से इसे बार-बार करना), शायद विपरीत।

+0

+1 सी ++ 11 के लिए उपयोगी पार्सिंग लाइब्रेरी की तरह दिखने के संदर्भ में +1: http://www.gbresearch.com/axe/ –

2

मैंने बूस्ट विधियों के साथ आईएनआई-पार्सिंग के बारे में एक अच्छा लेख पढ़ा है, इसे INI file reader using the spirit librarySilviu Simen द्वारा कहा जाता है।

यह आसान है।

+0

यह है 'क्लासिक' शैली भावना पुस्तकालय का उपयोग करके भी पुराना है। +1 बेकार – sehe