Properties 是 Java 平台處理配置文件的標準工具類,繼承自 Hashtable,鍵值皆為 String。廣泛應用於:資料庫連線參數、系統開關、國際化資源、外部化配置。本文系統講解 Properties 核心 API、檔案操作、XML 持久化、最佳實踐與避坑指南。
extends Hashtable<Object,Object> → 基本 Map 操作皆可用# 或 ! 開頭的註解行\ 續行、Unicode 轉義 (\uXXXX)Properties props = new Properties();
// 設值 (推薦)
props.setProperty("db.url", "jdbc:mysql://localhost:3306/mydb");
props.setProperty("db.user", "root");
props.setProperty("db.password", "secret");
// 取值 (含預設值)
String url = props.getProperty("db.url", "jdbc:h2:mem:test"); // 不存在回傳預設值
String driver = props.getProperty("db.driver"); // 不存在回傳 null
// 遍歷
props.forEach((k, v) -> System.out.println(k + "=" + v));
// 或
for (String name : props.stringPropertyNames()) {
System.out.println(name + "=" + props.getProperty(name));
}
// 刪除
props.remove("db.password"); // 繼承自 Hashtable
// 傳統寫法 (ISO-8859-1 編碼,中文會亂碼)
try (FileInputStream fis = new FileInputStream("config.properties")) {
props.load(fis);
}
// Java 9+ 指定 UTF-8 (推薦)
try (FileReader fr = new FileReader("config.properties", StandardCharsets.UTF_8)) {
props.load(fr);
}
// 從 classpath 載入 (常見於 Spring @PropertySource)
try (InputStream is = getClass().getClassLoader().getResourceAsStream("app.properties")) {
if (is != null) props.load(is);
}
try (FileWriter fw = new FileWriter("config.properties", StandardCharsets.UTF_8)) {
props.store(fw, "Database Configuration - Updated " + new Date());
}
// 輸出範例:
// #Database Configuration - Updated Mon May 20 10:30:00 CST 2024
// db.password=secret
// db.url=jdbc:mysql://localhost:3306/mydb
// db.user=root
// 寫入 XML
try (FileOutputStream fos = new FileOutputStream("config.xml")) {
props.storeToXML(fos, "Database Config", StandardCharsets.UTF_8.name());
}
// 從 XML 載入
try (FileInputStream fis = new FileInputStream("config.xml")) {
props.loadFromXML(fis);
}
XML 輸出範例:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "https://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Database Config</comment>
<entry key="db.url">jdbc:mysql://localhost:3306/mydb</entry>
<entry key="db.user">root</entry>
<entry key="db.password">secret</entry>
</properties>
Properties sysProps = System.getProperties();
Properties appProps = new Properties(sysProps); // 繼承系統屬性作為預設值
appProps.load(new FileInputStream("app.properties"));
// appProps 可讀取系統屬性,自身修改不影響系統屬性
// 應用啟動時根據 -Denv=prod 載入對應配置
String env = System.getProperty("env", "dev");
Properties props = new Properties();
props.load(new FileInputStream("application.properties")); // 基礎配置
props.load(new FileInputStream("application-" + env + ".properties")); // 環境覆蓋
public class PropsHelper {
private final Properties props;
public PropsHelper(Properties props) { this.props = props; }
public int getInt(String key, int def) {
String v = props.getProperty(key);
return v != null ? Integer.parseInt(v) : def;
}
public long getLong(String key, long def) { /* ... */ }
public boolean getBool(String key, boolean def) { /* ... */ }
public List getList(String key, String delimiter) { /* ... */ }
}
public class ReloadableProps {
private final String filePath;
private volatile Properties props;
private long lastModified;
public ReloadableProps(String filePath) { this.filePath = filePath; reload(); }
public synchronized void reload() {
File f = new File(filePath);
if (f.lastModified() > lastModified) {
Properties newProps = new Properties();
try (FileReader fr = new FileReader(f, StandardCharsets.UTF_8)) {
newProps.load(fr);
this.props = newProps;
this.lastModified = f.lastModified();
} catch (IOException e) { log.error("重載失敗", e); }
}
}
public String get(String key) { reload(); return props.getProperty(key); }
}
| 場景 | 問題 | 解決方案 |
|---|---|---|
| Properties 檔含中文 | ISO-8859-1 讀取亂碼 | Java 9+ 用 FileReader(StandardCharsets.UTF_8) / Files.newBufferedReader |
| 舊專案必須用 .properties | 無法直接存 UTF-8 | 用 native2ascii 轉義 \uXXXX、或改用 XML 格式 |
| ResourceBundle 讀取 | 強制 ISO-8859-1 | 改用 Properties.load(InputStream) 自行控制編碼 |
public final class ConfigManager {
private static final ConfigManager INSTANCE = new ConfigManager();
private final Properties props = new Properties();
private ConfigManager() {
load("application.properties");
String env = System.getProperty("app.env", "dev");
load("application-" + env + ".properties");
// 系統屬性最高優先級覆蓋
props.putAll(System.getProperties());
}
private void load(String path) {
try (InputStream is = getClass().getClassLoader().getResourceAsStream(path)) {
if (is != null) props.load(is);
} catch (IOException e) { log.warn("配置載入失敗:{}", path, e); }
}
public static ConfigManager get() { return INSTANCE; }
public String getString(String key) { return props.getProperty(key); }
public String getString(String key, String def) { return props.getProperty(key, def); }
public int getInt(String key, int def) { /* ... */ }
// ... 其他類型轉換
}