首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 讀寫 INI 設定檔完整實作:正則解析、區段支援、註解處理

     編輯:Java 程式設計入門

為什麼需要 INI 檔案支援?

Java 標準配置:Properties (key=value) 、XML (結構化)。但 INI 格式具備:

  • 區段 ([Section]) 邏輯分組
  • 註解 (; comment) 可讀性佳
  • 廣泛用於 Windows/C++/Delphi 專案,跨語言互通便利

JDK 無內建 INI 解析器,本文提供純 Java 實作 (無 JNI/外部依賴)。

INI 格式規範

; 全域註解
[Database]           ; 區段標題
host=localhost       ; 鍵值對
port=3306
; 區段內註解
username=root
password=secret

[Logging]
level=DEBUG
file=app.log

核心類別:ConfigurationFile


public final class ConfigurationFile {
    // 讀取單一值
    public static String getProfileString(String file, String section, 
                                          String variable, String defaultValue) 
            throws IOException { ... }
    
    // 修改單一值 (保留註解、格式)
    public static boolean setProfileString(String file, String section, 
                                           String variable, String value) 
            throws IOException { ... }
}

關鍵解析邏輯 (正則表達式)

區段識別

Pattern sectionPattern = Pattern.compile("^\\s*\\[\\s*(.+?)\\s*\\]\\s*$");
  • ^\s*\[:行首可有空白,接 [
  • \s*(.+?)\s*:非貪婪捕獲區段名
  • \]\s*$:接 ] 到行尾

鍵值對解析

// 移除行內註解
String line = rawLine.split(";")[0].trim();
// 分割鍵值 (僅第一個 =)
String[] kv = line.split("=", 2);
String key = kv[0].trim();
String val = kv.length > 1 ? kv[1].trim() : "";

getProfileString 完整流程

  1. 開啟 BufferedReader 逐行讀取
  2. 追蹤 isInTargetSection 狀態
  3. 遇到區段行 → 更新狀態
  4. 在目標區段內 → 解析鍵值 → 比對變數名 (忽略大小寫) → 找到即返回
  5. 讀完未找到 → 返回 defaultValue

setProfileString 完整流程 (保留格式與註解)

  1. 逐行讀取,累積到 StringBuilder fileContent
  2. 遇到目標鍵值 → 替換該行值,保留原行尾註解
  3. 寫入新值:key = newValue ; 原註解
  4. 剩餘行原樣追加
  5. BufferedWriter 覆寫原檔案

程式碼精簡版 (核心邏輯)


public static String getProfileString(String file, String section, String key, String def) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
        boolean inSection = false;
        String line;
        while ((line = br.readLine()) != null) {
            line = line.trim();
            String content = line.split(";")[0]; // 去註解
            // 區段判斷
            Matcher m = Pattern.compile("^\\[\\s*(.+?)\\s*\\]$").matcher(content);
            if (m.matches()) {
                inSection = m.group(1).equalsIgnoreCase(section);
                continue;
            }
            if (inSection) {
                String[] kv = content.split("=", 2);
                if (kv[0].trim().equalsIgnoreCase(key)) {
                    return kv.length > 1 ? kv[1].trim() : "";
                }
            }
        }
    }
    return def;
}

public static boolean setProfileString(String file, String section, String key, String value) throws IOException {
    List lines = Files.readAllLines(Paths.get(file), StandardCharsets.UTF_8);
    boolean inSection = false;
    boolean found = false;
    for (int i = 0; i < lines.size(); i++) {
        String raw = lines.get(i);
        String content = raw.split(";")[0].trim();
        String comment = raw.contains(";") ? ";" + raw.split(";")[1] : "";
        
        Matcher m = Pattern.compile("^\\[\\s*(.+?)\\s*\\]$").matcher(content);
        if (m.matches()) {
            inSection = m.group(1).equalsIgnoreCase(section);
            continue;
        }
        if (inSection && !found) {
            String[] kv = content.split("=", 2);
            if (kv[0].trim().equalsIgnoreCase(key)) {
                lines.set(i, kv[0].trim() + " = " + value + " " + comment);
                found = true;
            }
        }
    }
    if (found) Files.write(Paths.get(file), lines, StandardCharsets.UTF_8);
    return found;
}

測試範例


// config.ini
[Settings]
SampSize=100
; 取樣率

public static void main(String[] args) throws IOException {
    System.out.println(getProfileString("config.ini", "Settings", "SampSize", "0")); // 100
    setProfileString("config.ini", "Settings", "SampSize", "200");
    System.out.println(getProfileString("config.ini", "Settings", "SampSize", "0")); // 200
}

擴展建議

  • 支援 # 註解
  • 支援多行值 (續行符 \)
  • 型別轉換輔助:getInt(), getBoolean(), getList()
  • 快取機制:避免重複讀取同一檔案
  • 編碼參數化 (預設 UTF-8)

現代替代方案

總結

純 Java 實作 INI 讀寫僅需 正則解析 + 狀態機,核心邏輯 < 100 行。理解其原理,可按需裁剪擴展。生產環境建議採用成熟庫 (Commons Configuration) 以獲得更完善的錯誤處理、快取、多源合併等企業級特性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
庫特色Maven 坐標
Apache Commons Configuration支援 INI、XML、Properties、JNDI、資料庫等多源、統一 APIcommons-configuration:commons-configuration
ini4j專精 INI 格式、支援 Windows Registry 風格org.ini4j:ini4j
Typesafe Config (HOCON)JSON 超集、支援 include、變數替換、Akka/Play 專用com.typesafe:config