What is the easiest way to parse an INI file in Java?

Viewed 166561

I am writing a drop-in replacement for a legacy application in Java. One of the requirements is that the ini files that the older application used have to be read as-is into the new Java Application. The format of this ini files is the common windows style, with header sections and key=value pairs, using # as the character for commenting.

I tried using the Properties class from Java, but of course that won't work if there is name clashes between different headers.

So the question is, what would be the easiest way to read in this INI file and access the keys?

13 Answers

The library I've used is ini4j. It is lightweight and parses the ini files with ease. Also it uses no esoteric dependencies to 10,000 other jar files, as one of the design goals was to use only the standard Java API

This is an example on how the library is used:

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

As mentioned, ini4j can be used to achieve this. Let me show one other example.

If we have an INI file like this:

[header]
key = value

The following should display value to STDOUT:

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

Check the tutorials for more examples.

Here's a simple, yet powerful example, using the apache class 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");
}

Commons Configuration has a number of runtime dependencies. At a minimum, commons-lang and commons-logging are required. Depending on what you're doing with it, you may require additional libraries (see previous link for details).

Or with standard Java API you can use java.util.Properties:

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

Another option is Apache Commons Config also has a class for loading from INI files. It does have some runtime dependencies, but for INI files it should only require Commons collections, lang, and logging.

I've used Commons Config on projects with their properties and XML configurations. It is very easy to use and supports some pretty powerful features.

hoat4's solution is very elegant and simple. It works for all sane ini files. However, I have seen many that have un-escaped space characters in the key.
To solve this, I have downloaded and modified a copy of java.util.Properties. Though this is a little unorthodox, and short-term, the actual mods were but a few lines and quite simple. I will be puting forward a proposal to the JDK community to include the changes.

By adding an internal class variable:

private boolean _spaceCharOn = false;

I control the processing related to scanning for the key/value separation point. I replaced the space characters search code with a small private method that returns a boolean depending on the state of the above variable.

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

This method is used in two places within the private method load0(...).
There is also a public method to switch it on, but it would be better to use the original version of Properties if the space separator is not an issue for your application.

If there is interest, I would be willing to post the code to my IniFile.java file. It works with either version of Properties.

Using answer by @Aerospace, I realized that it is legitimate for INI files to have sections without any key-values. In this case, addition to the top-level map should happen before any key-values are found, ex (minimally updated for Java 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);
            }

You can use ini4j to convert INI to Properties

    Properties properties = new Properties();
    Ini ini = new Ini(new File("path/to/file"));
    ini.forEach((header, map) -> {
      map.forEach((subKey, value) -> {
        StringBuilder key = new StringBuilder(header);
        key.append("." + subKey);
        properties.put(key.toString(), value);
      });
    });

It is just as simple as this.....

//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");
Related