2008-10-10 6 views
85

Ich schreibe einen Drop-in-Ersatz für eine Legacy-Anwendung in Java. Eine der Anforderungen besteht darin, dass die Ini-Dateien, die die ältere Anwendung verwendet hat, unverändert in der neuen Java-Anwendung gelesen werden müssen. Das Format dieser ini-Dateien ist der gemeinsame Windows-Stil mit Header-Abschnitten und Schlüssel = Wert-Paaren, wobei # als Zeichen für das Kommentieren verwendet wird.Was ist der einfachste Weg, um eine INI-Datei in Java zu parsen?

Ich habe versucht, die Eigenschaften Klasse von Java verwenden, aber das ist natürlich nicht funktionieren, wenn es Namenskonflikte zwischen den verschiedenen Header ist.

Die Frage ist also, was wäre der einfachste Weg, in dieser INI-Datei zu lesen und die Schlüssel zugreifen?

Antwort

104

Die Bibliothek, die ich verwendet habe, ist ini4j. Es ist leicht und analysiert die Ini-Dateien mit Leichtigkeit. Auch verwendet er keine esoterischen Abhängigkeiten zu 10.000 anderen JAR-Dateien, als eines der Entwicklungsziele war nur der Standard-Java-API

Dies ist ein Beispiel für die Verwendung, wie die Bibliothek verwendet wird:

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)); 
+15

-Link: http://ini4j.sourceforge.net/ – alastairs

+1

nicht funktioniert, Fehler sagt „IniFile kann nicht sein, aufgelöst in einen Typ " – Caballero

+0

@Caballero ja es scheint, dass' IniFile' Klasse herausgenommen wurde, versuchen 'Ini ini = neue Ini (neue Datei ("/Pfad/zu/Datei "));' –

2

Eine weitere Option ist Apache Commons Config hat auch eine Klasse zum Laden von INI files. Es hat einige runtime dependencies, aber für INI-Dateien sollte es nur Commons-Sammlungen, lang und Protokollierung erfordern.

Ich habe Commons Config für Projekte mit ihren Eigenschaften und XML-Konfigurationen verwendet. Es ist sehr einfach zu bedienen und unterstützt einige ziemlich leistungsstarke Funktionen.

11

Oder mit Standard-Java-API können Sie java.util.Properties verwenden:

new Properties() props = rowProperties.load(new FileInputStream(path)); 
+9

Problem ist, dass die Struktur mit INI-Dateien Header hat. Die Property-Klasse kann nicht mit den Headern umgehen, und es könnte Namenskonflikte geben –

+2

Auch die 'Properties' Klasse erhält nicht richtig Werte, die \ – rds

+3

+1 für die einfache Lösung enthalten, aber passt nur einfache Konfigurationsdateien, wie Mario Ortegon und rds haben es bemerkt. – Benj

15

Hier ist ein einfaches, aber leistungsstarkes Beispiel der Apache-Klasse HierarchicalINIConfiguration mit:

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

Commons-Konfiguration hat eine Reihe von runtime dependencies. Mindestens sind commons-lang und commons-logging erforderlich. Abhängig davon, was Sie damit tun, benötigen Sie möglicherweise zusätzliche Bibliotheken (siehe vorherigen Link für Details).

+1

Dies wäre meine korrekte Antwort. Sehr einfach zu bedienen und vielseitig. – marcolopes

+0

Commons Konfigurationen nicht Sammlungen. – jantox

59

Als mentioned, ini4j kann verwendet werden, um dies zu erreichen. Lassen Sie mich ein anderes Beispiel zeigen.

Wenn wir eine INI-Datei wie folgt aussehen:

[header] 
key = value 

Folgendes sollte value zu STDOUT anzuzeigen:

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

prüfen the tutorials für weitere Beispiele.

+2

Ordentlich! Ich habe immer nur BufferedReader und ein bisschen Copy/Paste String-Parsing-Code verwendet, um meinen Anwendungen keine weitere Abhängigkeit hinzufügen zu müssen (die bei der Einführung von Drittanbieter-APIs für die einfachsten Aufgaben zu großen Problemen führen kann). Aber ich kann diese Art von Einfachheit nicht ignorieren. – Gimby

25

So einfach wie 80 Linien:

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)); 
    } 
} 
+0

+1 Einfach für die Verwendung von Regex Pattern/Matcher. Funktioniert wie ein Charm –

+0

Nicht eine perfekte Lösung, aber ein guter Ausgangspunkt, z. B. fehlende getSection() und getString() gibt nur defaultValue zurück, wenn der gesamte Abschnitt fehlt. –

+0

Was ist Leistungsunterschied zwischen solch einem Regx vs Arbeit mit String-Implementierung? – Ewoks

1

Ich persönlich bevor Confucious.

Es ist nett, da es keine externen Abhängigkeiten benötigt, es ist winzig - nur 16K, und lädt automatisch Ihre Ini-Datei bei der Initialisierung. Z.B.

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

3 Jahre später, Mark und der OP sind wahrscheinlich im Alter gestorben ... aber das ist ein wirklich guter Fund. – User

+3

Ich benutze einen Stock, um herumzukommen, aber immer noch am Leben und kick ' –

3

In 19 Zeilen, die java.util.Properties die sich in mehrere Abschnitte zu analysieren:

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("]")) 
       result.put(header.substring(1, header.length() - 1), 
         section = new Properties()); 
      else 
       section.put(key, value); 
      return null; 
     } 

    }.load(reader); 
    return result; 
} 
Verwandte Themen