जावा में INI फ़ाइल पार्स करने का सबसे आसान तरीका क्या है?


104

मैं जावा में एक विरासत आवेदन के लिए एक ड्रॉप-इन प्रतिस्थापन लिख रहा हूं। आवश्यकताओं में से एक यह है कि आईआई फाइलें जो पुराने एप्लिकेशन का उपयोग करती हैं, उन्हें नए जावा एप्लिकेशन के रूप में पढ़ा जाना चाहिए। इस ini फ़ाइलों का प्रारूप हेडर अनुभागों और कुंजी = मान युग्मों के साथ सामान्य विंडोज़ शैली है, टिप्पणी के लिए वर्ण के रूप में # का उपयोग करता है।

मैंने जावा से गुण वर्ग का उपयोग करने की कोशिश की, लेकिन निश्चित रूप से यह काम नहीं करेगा अगर विभिन्न हेडर के बीच नाम की झड़प हो।

तो सवाल यह है कि इस INI फ़ाइल को पढ़ने और कुंजियों तक पहुँचने का सबसे आसान तरीका क्या होगा?

जवाबों:


121

मैंने जिस लाइब्रेरी का उपयोग किया है, वह ini4j है । यह हल्का है और आसानी से ini फाइलों को पार्स करता है। इसके अलावा यह 10,000 अन्य जार फ़ाइलों के लिए कोई गूढ़ निर्भरता का उपयोग नहीं करता है, क्योंकि डिजाइन लक्ष्यों में से एक केवल मानक जावा एपीआई का उपयोग करना था

यह पुस्तकालय कैसे उपयोग किया जाता है, इस पर एक उदाहरण है:

Ini ini = new Ini(new File(filename));
java.util.prefs.Preferences prefs = new IniPreferences(ini);
System.out.println("grumpy/homePage: " + prefs.node("grumpy").get("homePage", null));

2
काम नहीं करता है, त्रुटि कहते हैं, "IniFile एक विशेष प्रकार के हल नहीं किया जा सकता है"
Caballero

@ कैबलेरो हां ऐसा लगता है कि IniFileकक्षा को बाहर कर दिया गया था, कोशिश करेंIni ini = new Ini(new File("/path/to/file"));
मेहदी करमोसली

2
ini4j.sourceforge.net/tutorial/OneMinuteTutorial.java.html शायद क्लास डेट बदलने पर भी डेट पर रहेंगे।
लोकाथोर

क्या यह बात अब भी काम कर रही है? 0.5.4 स्रोत डाउनलोड किया है और यह भी नहीं बनाया है, और यह एक लापता निर्भरता नहीं था .. इसके साथ परेशान करने के लिए समय के लायक नहीं है। इसके अलावा ini4j में कई अन्य बकवास भी हैं, जिनकी हमें आवश्यकता नहीं है, विंडोजेज़ रजिस्ट्री संपादन ... आओ। #LinuxMasterRace ... लेकिन मुझे लगता है कि अगर यह आपके लिए काम करता है, तो अपने आप को बाहर निकालें।
यूजर

मेरे द्वारा लिखी गई INI फ़ाइल के लिए, मुझे Wini"वन मिनट" ट्यूटोरियल में दर्शाए अनुसार कक्षा का उपयोग करना था ; prefs.node("something").get("val", null)जिस तरह से मैं उम्मीद काम नहीं किया।
एजी हैमर्थीफ़

65

जैसा कि उल्लेख किया गया है , इसे प्राप्त करने के लिए ini4j का उपयोग किया जा सकता है। मुझे एक और उदाहरण दिखाते हैं।

अगर हमारे पास इस तरह की एक INI फाइल है:

[header]
key = value

निम्नलिखित valueSTDOUT को प्रदर्शित करना चाहिए :

Ini ini = new Ini(new File("/path/to/file"));
System.out.println(ini.get("header", "key"));

अधिक उदाहरणों के लिए ट्यूटोरियल देखें ।


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

30

80 लाइनों के रूप में सरल:

package windows.prefs;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IniFile {

   private Pattern  _section  = Pattern.compile( "\\s*\\[([^]]*)\\]\\s*" );
   private Pattern  _keyValue = Pattern.compile( "\\s*([^=]*)=(.*)" );
   private Map< String,
      Map< String,
         String >>  _entries  = new HashMap<>();

   public IniFile( String path ) throws IOException {
      load( path );
   }

   public void load( String path ) throws IOException {
      try( BufferedReader br = new BufferedReader( new FileReader( path ))) {
         String line;
         String section = null;
         while(( line = br.readLine()) != null ) {
            Matcher m = _section.matcher( line );
            if( m.matches()) {
               section = m.group( 1 ).trim();
            }
            else if( section != null ) {
               m = _keyValue.matcher( line );
               if( m.matches()) {
                  String key   = m.group( 1 ).trim();
                  String value = m.group( 2 ).trim();
                  Map< String, String > kv = _entries.get( section );
                  if( kv == null ) {
                     _entries.put( section, kv = new HashMap<>());   
                  }
                  kv.put( key, value );
               }
            }
         }
      }
   }

   public String getString( String section, String key, String defaultvalue ) {
      Map< String, String > kv = _entries.get( section );
      if( kv == null ) {
         return defaultvalue;
      }
      return kv.get( key );
   }

   public int getInt( String section, String key, int defaultvalue ) {
      Map< String, String > kv = _entries.get( section );
      if( kv == null ) {
         return defaultvalue;
      }
      return Integer.parseInt( kv.get( key ));
   }

   public float getFloat( String section, String key, float defaultvalue ) {
      Map< String, String > kv = _entries.get( section );
      if( kv == null ) {
         return defaultvalue;
      }
      return Float.parseFloat( kv.get( key ));
   }

   public double getDouble( String section, String key, double defaultvalue ) {
      Map< String, String > kv = _entries.get( section );
      if( kv == null ) {
         return defaultvalue;
      }
      return Double.parseDouble( kv.get( key ));
   }
}

+1 केवल रेगेक्स पैटर्न / मिलान के उपयोग के लिए। एक आकर्षण की तरह काम करता है
kalelien

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

इस तरह के एक रेक्स बनाम स्ट्रिंग कार्यान्वयन के साथ काम करने के बीच प्रदर्शन अंतर क्या है?
Ewoks

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

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

16

यहाँ अपाचे वर्ग HierarchicalINIConfiguration का उपयोग करते हुए एक सरल, अभी तक शक्तिशाली उदाहरण है :

HierarchicalINIConfiguration iniConfObj = new HierarchicalINIConfiguration(iniFile); 

// Get Section names in ini file     
Set setOfSections = iniConfObj.getSections();
Iterator sectionNames = setOfSections.iterator();

while(sectionNames.hasNext()){

 String sectionName = sectionNames.next().toString();

 SubnodeConfiguration sObj = iniObj.getSection(sectionName);
 Iterator it1 =   sObj.getKeys();

    while (it1.hasNext()) {
    // Get element
    Object key = it1.next();
    System.out.print("Key " + key.toString() +  " Value " +  
                     sObj.getString(key.toString()) + "\n");
}

कॉमन्स कॉन्फ़िगरेशन में कई रनटाइम निर्भरताएँ होती हैं । कम से कम, कॉमन्स-लैंग और कॉमन्स-लॉगिंग की आवश्यकता होती है। आप इसके साथ क्या कर रहे हैं, इसके आधार पर, आपको अतिरिक्त पुस्तकालयों की आवश्यकता हो सकती है (विवरण के लिए पिछले लिंक देखें)।


1
यह मेरा सही उत्तर होगा। उपयोग करने के लिए बहुत सरल और बहुमुखी।
मार्कोलोप्स

कॉमन्स कॉन्फ़िगरेशन संग्रह नहीं।
जंतर

13

या मानक जावा एपीआई के साथ आप java.util.Properties का उपयोग कर सकते हैं :

Properties props = new Properties();
try (FileInputStream in = new FileInputStream(path)) {
    props.load(in);
}

12
समस्या यह है कि, ini फ़ाइलों के साथ, संरचना में हेडर हैं। प्रॉपर्टी क्लास को पता नहीं है कि हेडर को कैसे संभालना है, और नाम
क्लैश

2
इसके अलावा, Propertiesवर्ग ठीक से मूल्यों, जिनमें शामिल है \ नहीं मिलता है
आरडीएस

3
सरल समाधान के लिए +1, लेकिन केवल साधारण कॉन्फिग फाइलों में फिट बैठता है, जैसा कि मारियो ऑर्टेगन और आरडीएस ने देखा था।
बेंज

1
INI फ़ाइल में [अनुभाग], गुण फ़ाइल में असाइनमेंट शामिल हैं।
एयरोस्पेस

1
फ़ाइल प्रारूप: 1 / एक साधारण लाइन-ओरिएंटेड या 2 / एक सरल XML प्रारूप या 3 / एक साधारण लाइन-उन्मुख, ISO 8859-1 ( यूनिकोड से बचकर + native2asciiअन्य एन्कोडिंग के लिए उपयोग ) का उपयोग
करके

10

18 लाइनों में, java.util.Propertiesकई खंडों में पार्स करने के लिए विस्तार :

public static Map<String, Properties> parseINI(Reader reader) throws IOException {
    Map<String, Properties> result = new HashMap();
    new Properties() {

        private Properties section;

        @Override
        public Object put(Object key, Object value) {
            String header = (((String) key) + " " + value).trim();
            if (header.startsWith("[") && header.endsWith("]"))
                return result.put(header.substring(1, header.length() - 1), 
                        section = new Properties());
            else
                return section.put(key, value);
        }

    }.load(reader);
    return result;
}

2

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

मैंने अपनी संपत्तियों और XML कॉन्फ़िगरेशन के साथ प्रोजेक्ट्स पर Commons config का उपयोग किया है। कुछ बहुत शक्तिशाली सुविधाओं का उपयोग करना और उनका समर्थन करना बहुत आसान है।



2

मैं व्यक्तिगत रूप से कन्फ्यूज रहना पसंद करता हूं ।

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

Configurable config = Configuration.getInstance();  
String host = config.getStringValue("host");   
int port = config.getIntValue("port"); 
new Connection(host, port);

3 साल बाद, मार्क और ओपी की शायद बुढ़ापे में मृत्यु हो गई है ... लेकिन यह वास्तव में अच्छा है।
यूजर

6
मैं चारों ओर पाने के लिए एक बेंत का उपयोग करता हूं, लेकिन फिर भी जीवित और
किकिन करता हूं

@ मारियो ऑर्टगॉन: यह सुनकर बहुत अच्छा लगा!
יךו אוהב אות

0

hoat4 का समाधान बहुत ही सुरुचिपूर्ण और सरल है। यह सभी सनी इन फाइलों के लिए काम करता है । हालाँकि, मैंने ऐसे कई देखे हैं जो कुंजी में अन-एस्केप अंतरिक्ष वर्ण हैं ।
इसे हल करने के लिए, मैंने इसकी एक प्रति डाउनलोड और संशोधित की है java.util.Properties। हालांकि यह थोड़ा अपरंपरागत है, और अल्पकालिक है, वास्तविक मोड कुछ लाइनें और काफी सरल थे। परिवर्तनों को शामिल करने के लिए मैं जेडीके समुदाय के सामने एक प्रस्ताव रखूंगा।

एक आंतरिक वर्ग चर जोड़कर:

private boolean _spaceCharOn = false;

मैं कुंजी / मूल्य पृथक्करण बिंदु के लिए स्कैनिंग से संबंधित प्रसंस्करण को नियंत्रित करता हूं। मैंने अंतरिक्ष वर्ण खोज कोड को एक छोटी निजी विधि से बदल दिया है जो उपरोक्त चर की स्थिति के आधार पर एक बूलियन देता है।

private boolean isSpaceSeparator(char c) {
    if (_spaceCharOn) {
        return (c == ' ' || c == '\t' || c == '\f');
    } else {
        return (c == '\t' || c == '\f');
    }
}

इस पद्धति का उपयोग निजी पद्धति के भीतर दो स्थानों पर किया जाता है load0(...)
इसे स्विच करने के लिए एक सार्वजनिक विधि भी है, लेकिन यह बेहतर होगा कि Propertiesयदि आपके एप्लिकेशन के लिए स्पेस सेपरेटर कोई समस्या नहीं है , तो इसके मूल संस्करण का उपयोग करें ।

यदि रुचि है, तो मैं अपनी IniFile.javaफ़ाइल पर कोड पोस्ट करने को तैयार हूं । यह या तो संस्करण के साथ काम करता है Properties


0

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

            Path location = ...;
            try (BufferedReader br = new BufferedReader(new FileReader(location.toFile()))) {
                String line;
                String section = null;
                while ((line = br.readLine()) != null) {
                    Matcher m = this.section.matcher(line);
                    if (m.matches()) {
                        section = m.group(1).trim();
                        entries.computeIfAbsent(section, k -> new HashMap<>());
                    } else if (section != null) {
                        m = keyValue.matcher(line);
                        if (m.matches()) {
                            String key = m.group(1).trim();
                            String value = m.group(2).trim();
                            entries.get(section).put(key, value);
                        }
                    }
                }
            } catch (IOException ex) {
                System.err.println("Failed to read and parse INI file '" + location + "', " + ex.getMessage());
                ex.printStackTrace(System.err);
            }

-2

यह बस के रूप में सरल है .....

//import java.io.FileInputStream;
//import java.io.FileInputStream;

Properties prop = new Properties();
//c:\\myapp\\config.ini is the location of the ini file
//ini file should look like host=localhost
prop.load(new FileInputStream("c:\\myapp\\config.ini"));
String host = prop.getProperty("host");

1
यह INI सेक्शन को हैंडल नहीं करता है
इगोर मेल्निचेंको
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.