A lightweight Java library for reading, writing, and editing IniFileNg-format .ini files. The entire file is held in memory as a single String and all operations use string search-and-replace, so comments, indentation, tabs, and inline annotations are preserved exactly as they appear in the original file.
IniFileNg uses a three-level hierarchy: Groups contain Sites, and each Site contains key/value pairs.
# IniFileNg - IniFile Next Gen
#
{GroupOne} ; Group One
[kelly] ; Site kelly
address = 192.168.128.23
port = 8554
type = RTSP TCP
user = root
password = agilemesh1
isCell = false
[End]
[Wiles] ; Site Wiles
address = 192.168.128.24
port = 554
type = RTSP UDP
user = root
password = agilemesh1
isCell = false
[End]
{End}
{GroupTwo} ; Group Two
[MegaPixel] ; Site MegaPixel
address = 192.168.129.33 ; IP Address
port = 8554
type = RTSP TCP
user = root
password = agilemesh1
isCell = false
[End]
{End}| Element | Syntax | Notes |
|---|---|---|
| Group open | {GroupName} |
Curly braces, one per line |
| Group close | {End} |
Case-insensitive |
| Site open | [SiteName] |
Square brackets, indented inside a group |
| Site close | [End] |
Case-insensitive |
| Key/value | key = value |
Indented inside a site |
| Comment | ; text |
Anywhere after a # header line or inline after a value |
| Header comment | # text |
At the top of the file |
- Indentation is flexible — tabs and spaces are both accepted.
- Inline comments (
; text) after a value are preserved untouched by all operations. - Group and site names are matched case-insensitively.
Copy IniFileNg.java into your project under the package com.inifileng and compile with any Java 8+ compiler:
javac src/main/java/com/inifileng/IniFileNg.javaNo external dependencies are required.
import com.inifileng.IniFileNg;
import java.util.LinkedHashMap;
import java.util.Map;
// Load an existing file
IniFileNg ini = new IniFileNg("config.ini");
// Read a value
String addr = ini.getValue("GroupOne", "kelly", "address");
// → "192.168.128.23"
// Update a value (inline comment is preserved)
ini.updateValue("GroupOne", "kelly", "port", "9999");
// Add a new key to an existing site
ini.addKey("GroupOne", "kelly", "timeout", "30");
// Save back to disk
ini.save("config.ini");// Create an empty document
IniFileNg ini = new IniFileNg();
// Load from a file path string
IniFileNg ini = new IniFileNg("path/to/config.ini");
// Load from a java.io.File
IniFileNg ini = new IniFileNg(new File("config.ini"));
// Load or reload at any time
ini.load("path/to/config.ini");
// Save to disk
ini.save("path/to/config.ini");
// Access or replace the raw string content directly
String raw = ini.getRawContent();
ini.setRawContent(raw);// Get the value of a key (inline comments are stripped; returns null if not found)
String value = ini.getValue("GroupTwo", "MegaPixel", "address");
// Get all key/value pairs for a site as a LinkedHashMap (insertion order preserved)
// Inline comments are stripped from values; returns null if group or site not found
LinkedHashMap<String, String> site = ini.getSite("GroupOne", "kelly");
// → { "address" → "192.168.128.23", "port" → "8554", "type" → "RTSP TCP", ... }
// List all group names
List<String> groups = ini.listGroups();
// List all site names within a group
List<String> sites = ini.listSites("GroupOne");
// List all key names within a site
List<String> keys = ini.listKeys("GroupOne", "kelly");
// Existence checks
boolean exists = ini.groupExists("GroupTwo");
boolean exists = ini.siteExists("GroupOne", "Wiles");
boolean exists = ini.keyExists("GroupOne", "kelly", "port");// Change the value of an existing key
// Returns true on success, false if the group/site/key is not found
boolean ok = ini.updateValue("GroupOne", "kelly", "port", "9999");Inline comments and surrounding whitespace are preserved exactly:
; Before
address = 192.168.129.33 ; IP Address
; After updateValue("GroupTwo", "MegaPixel", "address", "10.0.0.1")
address = 10.0.0.1 ; IP Address// Add a new key to an existing site (no-op if key already exists)
// Returns true if added, false if the key already existed or site was not found
boolean ok = ini.addKey("GroupOne", "Wiles", "timeout", "30");
// Add a new site to an existing group (no-op if site already exists)
// Use LinkedHashMap to control key insertion order
Map<String, String> keys = new LinkedHashMap<>();
keys.put("address", "10.0.0.50");
keys.put("port", "554");
keys.put("type", "RTSP TCP");
keys.put("user", "admin");
keys.put("password", "secret");
keys.put("isCell", "false");
boolean ok = ini.addSite("GroupTwo", "NewCam", keys);
// Add a new empty group at the end of the file (no-op if group already exists)
boolean ok = ini.addGroup("GroupThree");// Remove a single key from a site
// Returns true if removed, false if not found
boolean ok = ini.deleteKey("GroupOne", "kelly", "user");
// Remove an entire site (including its [End]) from a group
boolean ok = ini.deleteSite("GroupTwo", "MegaPixel");
// Remove an entire group (including all its sites and {End})
boolean ok = ini.deleteGroup("GroupOne");// Rename a group
boolean ok = ini.renameGroup("GroupOne", "CameraGroupA");
// Rename a site within a group
boolean ok = ini.renameSite("GroupOne", "kelly", "KellyStream");Every mutating method returns a boolean:
| Return | Meaning |
|---|---|
true |
Operation succeeded |
false |
Target not found, or duplicate detected (for add operations) |
No exceptions are thrown for logical failures (not found, duplicate). IOException is only thrown by load() and save().
String-based storage — the file lives in memory as one String. Every operation slices the string into before/target/after segments, performs its replacement, and stitches the pieces back together. This means the file is never parsed into an object tree, so the original formatting is never reconstructed or reformatted.
Comment preservation — updateValue uses a two-pass regex strategy: the first pass captures the full rest-of-line after key =, and the second splits the value from any trailing \t; comment fragment. Only the value portion is swapped out.
Indent detection — addSite and addKey inspect the surrounding block to detect the existing indentation style and match it automatically.
Case-insensitive matching — all group, site, and key lookups are case-insensitive, but names are stored exactly as provided when creating new entries.
Non-nested groups — groups are not nestable. The {End} closing tag is matched to the first {End} following the group's opening line.
# Compile
javac -d out src/inifileng/IniFileNg.java \
src/utest/IniFileNgTest.java
# Run
java -cp out com.inifileng.IniFileNgTestExpected output:
--- READ TESTS ---
PASS listGroups size
...
==============================================
Results: 72 passed, 0 failed
==============================================
MIT — free to use, modify, and distribute.