.properties 是 Java 生態最經典的配置檔格式,採「鍵=值」純文字結構,支援註解(# 或 !),廣泛用於資料庫連線、系統參數、國際化資源等場景。本文系統整理 Properties 核心 API、多種載入路徑策略、讀寫完整代碼、Classpath 機制深度解析,並提供開箱即用的工具類。
#################################
# 工商報表應用 IcisReport 配置文件
# 日期:2006年11月21日
#################################
# 說明:業務系統與報表系統分離部署
# IcisReport 的 IP
IcisReport.server.ip=192.168.3.143
# IcisReport 的埠號
IcisReport.server.port=8080
# 上下文路徑
IcisReport.contextPath=/IcisReport
| 方法 | 說明 |
|---|---|
getProperty(String key) | 依鍵取值,找不到回傳 null |
getProperty(String key, String defaultValue) | 指定預設值 |
load(InputStream inStream) | 從輸入流載入鍵值對(ISO-8859-1 編碼) |
load(Reader reader) | 從字元流載入(可指定 UTF-8 等編碼)Java 1.6+ |
setProperty(String key, String value) | 設定鍵值(同步至內部 Hashtable) |
store(OutputStream out, String comments) | 寫入輸出流,標頭寫入 comments |
store(Writer writer, String comments) | 字元流寫入(可指定編碼)Java 1.6+ |
clear() | 清空所有鍵值 |
keySet() / propertyNames() | 取得所有鍵集合 |
/ 開頭),適用於 JAR 內部資源、Maven src/main/resources。/),通用性最強,推薦首選。/etc/app/config.properties),不受 Classpath 限制。file_zh_TW.properties 等變體,不支援寫入,且快取機制導致修改不即時生效。package com.example.util;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public final class PropertiesUtil {
private PropertiesUtil() {}
/** 讀取單一鍵值 */
public static String get(String path, String key) {
try (InputStream in = resolveInputStream(path)) {
Properties props = new Properties();
props.load(in);
return props.getProperty(key);
} catch (IOException e) {
throw new RuntimeException("讀取配置失敗: " + path, e);
}
}
/** 讀取全部鍵值 */
public static Map<String, String> getAll(String path) {
try (InputStream in = resolveInputStream(path)) {
Properties props = new Properties();
props.load(in);
Map<String, String> result = new ConcurrentHashMap<>();
for (String key : props.stringPropertyNames()) {
result.put(key, props.getProperty(key));
}
return result;
} catch (IOException e) {
throw new RuntimeException("讀取配置失敗: " + path, e);
}
}
/** 寫入/更新鍵值(自動建立檔案與父目錄) */
public static void set(String path, String key, String value, String comment) {
File file = new File(path);
Properties props = new Properties();
// 1. 讀取現有內容
if (file.exists()) {
try (InputStream in = new FileInputStream(file)) {
props.load(in);
} catch (IOException e) {
throw new RuntimeException("讀取現有配置失敗", e);
}
} else {
file.getParentFile().mkdirs(); // 自動建立目錄
}
// 2. 更新值
props.setProperty(key, value);
// 3. 寫回檔案(UTF-8)
try (OutputStream out = new FileOutputStream(file);
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
props.store(writer, comment != null ? comment : "Updated by PropertiesUtil at " + new Date());
} catch (IOException e) {
throw new RuntimeException("寫入配置失敗: " + path, e);
}
}
/** 解析輸入流:優先 Classpath,再嘗試檔案系統 */
private static InputStream resolveInputStream(String path) throws IOException {
// 1. ClassLoader 根目錄
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
if (in != null) return in;
// 2. 檔案系統絕對/相對路徑
File file = new File(path);
if (file.exists()) return new FileInputStream(file);
throw new FileNotFoundException("找不到配置檔: " + path + " (Classpath 或檔案系統均無)");
}
}
.properties 放在 src/main/resources(Maven)或 src 根目錄,編譯後進入 target/classes,屬於 Classpath。WEB-INF/classes 或 WEB-INF/lib 內的 JAR 中。-Dspring.config.location=file:/opt/app/config/ 或手動 new FileInputStream("/opt/app/config/app.properties")。config.properties 卻放在 src/main/resources/com/example/ 下 → 應用 com/example/config.properties 或移動檔案。Class.getResourceAsStream("config.properties")(無 /)→ 相對於類所在包,非 Classpath 根。src/main/resources 下檔案但未重新編譯/打包 → 運行時仍讀舊版本。Properties.load(InputStream) 強制使用 ISO-8859-1,中文會變亂碼(如 \u4e2d\u6587)。load(Reader) / store(Writer) 搭配 StandardCharsets.UTF_8。native2ascii 工具轉義或改用 XML 格式 loadFromXML/storeToXML(天然 UTF-8)。Properties 非執行緒安全,建議快取至 ConcurrentHashMap 或使用 Apache Commons Configuration / Spring @ConfigurationProperties。掌握 Properties 的載入機制、編碼處理與路徑策略,能解決 90% 的配置讀取疑難雜症。配合上述工具類,即可在專案中統一、安全、高效地管理配置。