फाइल से सेटिंग लोड और स्टोर कहां करें?


9

मुझे लगता है कि यह सवाल ज्यादातर प्रोग्राम पर लागू होना चाहिए जो एक फाइल से सेटिंग लोड करता है। मेरा प्रश्न एक प्रोग्रामिंग दृष्टिकोण से है, और यह वास्तव में विभिन्न वर्गों और पहुंच के संदर्भ में फ़ाइल से सेटिंग्स के लोडिंग से कैसे निपटना है। उदाहरण के लिए:

  • यदि किसी प्रोग्राम में एक साधारण settings.iniफ़ाइल होती है, तो क्या उसकी सामग्री load()को किसी वर्ग की विधि में लोड किया जाना चाहिए , या शायद कंस्ट्रक्टर?
  • क्या मूल्यों को public staticचर में संग्रहीत किया जाना चाहिए, या staticगुणों को प्राप्त करने और सेट करने के तरीके होने चाहिए ?
  • फ़ाइल के विद्यमान होने या न पढ़ने योग्य होने की स्थिति में क्या होना चाहिए? आप कार्यक्रम के बाकी हिस्सों को कैसे बताएंगे कि यह उन संपत्तियों को प्राप्त नहीं कर सकता है।
  • आदि।

मैं उम्मीद कर रहा हूँ कि मैं इसे यहाँ सही जगह पर पूछ रहा हूँ। मैं सवाल को भाषा अज्ञेय के रूप में संभव बनाना चाहता था, लेकिन मैं मुख्य रूप से उन भाषाओं पर ध्यान केंद्रित कर रहा हूं जिनमें विरासत जैसी चीजें हैं - विशेष रूप से जावा और सी # .NET।


1
.NET के लिए, सेटिंग्स प्राप्त करने के लिए App.config और System.Configuration.ConfigurationManager वर्ग का उपयोग करना सबसे अच्छा है
गिब्सन


Stackoverflow के पास इस पर बहुत सारे उत्तर हैं। त्वरित खोज से पता चलता है: stackoverflow.com/questions/114527/… और stackoverflow.com/questions/13043530/… MSDN पर भी बहुत सारी जानकारी होगी, यहाँ से शुरू करें msdn.microsoft.com/en-us/usibrary/ms228063(v = vs.100) .aspx और msdn.microsoft.com/en-us/library/ms184658(v=vs.110).aspx
गिब्सन

@ गिब्सन उन लिंक्स के लिए धन्यवाद। वे बहुत उपयोगी होंगे।
एंडी

जवाबों:


8

यह वास्तव में एक बहुत महत्वपूर्ण सवाल है और यह अक्सर गलत तरीके से किया जाता है क्योंकि इसे पर्याप्त महत्व नहीं दिया जाता है, भले ही यह आपके आवेदन का एक बहुत बड़ा हिस्सा हो। यहाँ मेरे दिशानिर्देश हैं:

आपकी कॉन्फ़िगर क्लास, जिसमें सभी सेटिंग्स हैं, बस एक सादा पुराना डेटा टाइप, स्ट्रक्चर / क्लास होना चाहिए:

class Config {
    int prop1;
    float prop2;
    SubConfig subConfig;
}

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

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

आपको यह करते हुए फ़ील्ड के रूप में सभी सेटिंग्स में टाइप करने में आलसी नहीं होना चाहिए:

class Config {
    Dictionary<string, string> values;
};

यह आकर्षक है क्योंकि इसका मतलब है कि आप एक सामान्यीकृत क्रमबद्धता वर्ग लिख सकते हैं जिसे यह जानने की आवश्यकता नहीं है कि यह किस क्षेत्र से काम कर रहा है, लेकिन यह गलत है और मैं समझाता हूं कि एक क्षण में क्यों।

विन्यास का सीरियलाइजेशन पूरी तरह से अलग वर्ग में किया जाता है। ऐसा करने के लिए आप जो भी API या लाइब्रेरी का उपयोग करते हैं, आपके क्रमांकन फ़ंक्शन के बॉडी में ऐसी प्रविष्टियाँ होनी चाहिए जो मूल रूप से फ़ाइल में पथ / कुंजी से ऑब्जेक्ट पर फ़ील्ड में फ़ील्ड के लिए हो। कुछ भाषाएं अच्छी आत्मनिरीक्षण प्रदान करती हैं और आपके लिए यह बॉक्स से बाहर कर सकती हैं, अन्य आपको स्पष्ट रूप से मैपिंग लिखना होगा, लेकिन महत्वपूर्ण बात यह है कि आपको केवल एक बार मैपिंग लिखना होगा। उदाहरण के लिए इस उद्धरण पर विचार करें जिसे मैंने c ++ बूस्ट प्रोग्राम विकल्प पार्सर प्रलेखन से अनुकूलित किया है:

struct Config {
   int opt;
} conf;
po::options_description desc("Allowed options");
desc.add_options()
    ("optimization", po::value<int>(&conf.opt)->default_value(10);

ध्यान दें कि अंतिम पंक्ति मूल रूप से कॉन्फ़िगर करने के लिए "ऑप्टिमाइज़ेशन" मैप्स :: ऑप्ट कहती है और यह भी कि आपके द्वारा अपेक्षित प्रकार की घोषणा है। आप चाहते हैं कि यदि आप फ़ाइल से पैरामीटर वास्तव में फ्लोट या इंट नहीं है, या मौजूद नहीं है, तो टाइप करने के लिए कॉन्फ़िगर की रीडिंग विफल हो सकती है। Ie विफलता तब होनी चाहिए जब आप फ़ाइल पढ़ते हैं क्योंकि समस्या फ़ाइल के प्रारूप / सत्यापन के साथ है और आपको एक अपवाद / रिटर्न कोड फेंकना चाहिए और सटीक समस्या की रिपोर्ट करनी चाहिए। आपको इस कार्यक्रम में बाद में देरी नहीं करनी चाहिए। इसीलिए आपको किसी भी तरह की डिक्शनरी को पकड़ने के लिए लुभाया नहीं जाना चाहिए। जैसा कि ऊपर उल्लेख किया गया है कि फाइल पढ़ने पर फेल नहीं होगी - जब तक कि मूल्य की आवश्यकता न हो, कास्टिंग में देरी हो जाती है।

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

आदर्श रूप से आप अपने प्रोग्राम में एक जगह फ़ाइल में पढ़ते हैं अर्थात आपके पास केवल " ConfigReader" का एक उदाहरण है । हालाँकि, यदि आप कॉन्फिगरेशन इंस्टेंस प्राप्त करने से जूझ रहे हैं, जहाँ आपको इसकी आवश्यकता है, जहाँ आपको इसकी आवश्यकता है, वहां एक दूसरे कॉन्फिगरर के साथ होना बेहतर है, क्योंकि यह ग्लोबल कॉन्फिगरेशन का परिचय देता है (जिसका मैं अनुमान लगा रहा हूँ कि ओपी का अर्थ "स्टेटिक" है "), जो कि मुझे मेरे अगले बिंदु पर ले आता है:

सिंगलटन के मोहक सायरन गीत से बचें: "मैं आपको उस क्लास क्लास को पास करने के लिए बचाऊंगा, आपके सभी निर्माता प्यारे और साफ होंगे। चलिए, यह बहुत आसान होगा।" सत्य एक अच्छी तरह से डिजाइन किए गए परीक्षण योग्य वास्तुकला के साथ है, आपको शायद ही अपने एप्लिकेशन के कई वर्गों के माध्यम से कॉन्फ़िगर वर्ग या इसके कुछ हिस्सों को पारित करने की आवश्यकता होगी। आप क्या पाएंगे, अपने शीर्ष स्तर के वर्ग में, आपका मुख्य () फ़ंक्शन या जो भी हो, आप व्यक्तिगत मूल्यों में अंतर को उजागर करेंगे, जो आप अपने घटक वर्गों को तर्क के रूप में प्रदान करेंगे, जिसे आप फिर से एक साथ रखते हैं (मैनुअल निर्भरता इंजेक्शन)। एक सिंगलटन / ग्लोबल / स्टैटिक कॉन्फिडेंस यूनिट यूनिट को आपके एप्लिकेशन को कार्यान्वित करने और समझने के लिए बहुत कठिन बना देगा - जैसे यह आपकी टीम में नए डेवलपर्स को भ्रमित करेगा, जो यह नहीं जान पाएंगे कि उन्हें सामान का परीक्षण करने के लिए ग्लोबल स्टेट सेट करना है।

यदि आपकी भाषा गुणों का समर्थन करती है तो आपको उन्हें इस उद्देश्य के लिए उपयोग करना चाहिए। इसका कारण यह है कि 'व्युत्पन्न' कॉन्फ़िगरेशन सेटिंग्स को जोड़ना बहुत आसान होगा जो एक या अधिक अन्य सेटिंग्स पर निर्भर करता है। जैसे

int Prop1 { get; }
int Prop2 { get; }
int Prop3 { get { return Prop1*Prop2; }

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

पूर्वता के क्रम में आपको अलग-अलग स्थानों से विलय करने और कई कॉन्फ़िगरेशन लेने के लिए एक सिस्टम की आवश्यकता हो सकती है। पूर्वता के उस क्रम को सभी डेवलपर्स / उपयोगकर्ता को अच्छी तरह से परिभाषित और समझना चाहिए। उदाहरण के लिए विंडोज़ रजिस्ट्री HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE पर विचार करें। आपको यह कार्यात्मक शैली करनी चाहिए ताकि आप अपने विन्यास को केवल पढ़ने के लिए रख सकें:

final_conf = merge(user_conf, machine_conf)

बजाय:

conf.update(user_conf)

अंत में मुझे यह जोड़ना चाहिए कि यदि आपका चुना हुआ ढांचा / भाषा अपने स्वयं के अंतर्निहित, प्रसिद्ध कॉन्फ़िगरेशन तंत्र प्रदान करता है, तो आपको अपने स्वयं के रोल के बजाय इसका उपयोग करने के लाभों पर विचार करना चाहिए।

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


+1 जवाब के लिए धन्यवाद। पहले जब मैंने उपयोगकर्ता सेटिंग्स संग्रहीत की हैं, तो मैंने एक फ़ाइल से पढ़ा है जैसे .iniकि यह मानव पठनीय है, लेकिन क्या आप सुझाव दे रहे हैं कि मुझे चर के साथ एक वर्ग को क्रमबद्ध करना चाहिए?
एंडी

.ini को पार्स करना आसान है, और इसमें बहुत सारे एपीआई भी शामिल हैं। एक संभावित प्रारूप के रूप में .ini भी शामिल है। मैं सुझाव दे रहा हूं कि आप पाठ्यपुस्तक के पार्सिंग कार्य को करने में मदद करने के लिए ऐसे API का उपयोग करते हैं, लेकिन अंतिम परिणाम यह होना चाहिए कि आपने POD वर्ग को आरंभीकृत कर लिया है। मैं किसी प्रारूप से किसी वर्ग के क्षेत्रों में कॉपी करने या पढ़ने के सामान्य अर्थ में क्रमबद्ध धारावाहिक का उपयोग करता हूं, न कि किसी वर्ग को सीधे बाइनरी / से क्रमबद्ध करने की अधिक विशिष्ट परिभाषा (जैसा कि आमतौर पर java.io.Serializable के लिए समझा जाता है। )।
बेनेडिक्ट

अब मैं थोड़ा बेहतर समझ रहा हूं। तो अनिवार्य रूप से आप कह रहे हैं कि सभी फ़ील्ड / सेटिंग्स के साथ एक वर्ग है, और फ़ाइल से उस कक्षा में मान सेट करने के लिए एक और है? फिर, मुझे अन्य कक्षाओं में पहली कक्षा से कैसे मान मिलना चाहिए?
एंडी

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

तो, आप यह कैसे सुझाएंगे कि यदि इनहेरिटेंस को शामिल करने की आवश्यकता नहीं है, तो कॉन्फ़िगर ऑब्जेक्ट को कक्षाओं में पास किया जाता है? एक निर्माता के माध्यम से? तो, कार्यक्रम की मुख्य विधि में, पाठक वर्ग शुरू किया जाता है जो विन्यास वर्ग में मूल्यों को संग्रहीत करता है, फिर मुख्य विधि विन्यास वस्तु, या अन्य वर्गों के लिए अलग-अलग चर पास करती है?
एंडी

4

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

इसके अलावा, यह आवेदन पर "क्या होता है जब चीजें विफल हो जाती हैं" का बोझ डालता है, जो सबसे अच्छा जानता है कि विफलता का क्या मतलब है।

और यह इकाई परीक्षण के लिए आसान टन बनाता है जब आप केवल फाइल सिस्टम को छूने या स्थैतिक उपयोग द्वारा शुरू किए गए संगामित मुद्दों से निपटने के बजाय एक कॉन्फ़िगरेशन ऑब्जेक्ट में पास कर सकते हैं।


आपके उत्तर के लिए धन्यवाद, लेकिन मैं इसे काफी नहीं समझता। मैं एप्लिकेशन लिखते समय बात कर रहा हूं, इसलिए कॉन्फ़िगरेशन से निपटने के लिए कुछ भी नहीं है, और इसलिए, एक प्रोग्रामर के रूप में, मुझे पता है कि विफलता का क्या मतलब है।
एंडी

@ कैंडी - यकीन है, लेकिन अगर मॉड्यूल सीधे कॉन्फ़िगरेशन का उपयोग करते हैं, तो वे नहीं जानते कि वे किस संदर्भ में काम कर रहे हैं, इसलिए वे यह निर्धारित नहीं कर सकते हैं कि कॉन्फ़िगरेशन मुद्दों को कैसे संभालना है। यदि आवेदन लोडिंग कर रहा है, तो यह किसी भी मुद्दे से निपट सकता है, क्योंकि यह संदर्भ जानता है। कुछ ऐप्स डिफ़ॉल्ट मान से अधिक विफल होना चाहते हैं, दूसरों को गर्भपात करना चाहते हैं, आदि
Telastyn

यहां स्पष्ट करने के लिए, मॉड्यूल द्वारा आप कक्षाओं, या किसी कार्यक्रम के लिए वास्तविक एक्सटेंशन का जिक्र कर रहे हैं? क्योंकि मैं इस बारे में पूछ रहा हूं कि कोड के अंदर वास्तव में सेटिंग्स को मुख्य कार्यक्रम में कैसे स्टोर किया जाए और अन्य कक्षाओं को सेटिंग्स तक कैसे पहुंचने दिया जाए। इसलिए मैं एक कॉन्फ़िगरेशन फ़ाइल लोड करना चाहता हूं और फिर सेटिंग को कहीं और / किसी भी तरह से स्टोर करना चाहता हूं, इसलिए मुझे फ़ाइल का संदर्भ नहीं रखना है।
एंडी

0

यदि आप कक्षाओं के प्रोग्रामिंग के लिए .NET का उपयोग कर रहे हैं, तो आपके पास संसाधन, web.config, या यहां तक ​​कि कस्टम फ़ाइल जैसे विभिन्न विकल्प हैं।

यदि आप संसाधन या web.config का उपयोग करते हैं, तो डेटा वास्तव में XML फ़ाइल में संग्रहीत किया जाता है, लेकिन, लोडिंग तेज है।

इन फ़ाइलों से डेटा को पुनर्प्राप्त करना और उन्हें किसी अन्य स्थान पर संग्रहीत करना स्मृति के दोहरे उपयोग की तरह होगा क्योंकि ये डिफ़ॉल्ट रूप से मेमोरी में लोड होते हैं।

किसी भी अन्य फ़ाइल या प्रोग्रामिंग भाषा के लिए, बेनेडिक्ट द्वारा उपरोक्त उत्तर काम करेगा।


आपके उत्तर के लिए धन्यवाद और धीमे उत्तर के लिए क्षमा करें। संसाधनों का उपयोग करना एक अच्छा विकल्प होगा, लेकिन मैंने अभी महसूस किया है कि यह शायद मेरे लिए सबसे अच्छा विकल्प नहीं है, क्योंकि मैं अन्य भाषाओं में समान कार्यक्रम विकसित करने की योजना बना रहा हूं, इसलिए मेरे पास XML या JSON फ़ाइल होगी, लेकिन इसे अपनी कक्षा में पढ़ें ताकि अन्य प्रोग्रामिंग भाषाओं में उसी फ़ाइल को पढ़ा जा सके।
एंडी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.