JDK 1.4 引入 java.util.prefs.Preferences API,為 Java 程序提供了跨平台的持久化配置存儲能力。在 Windows 平台上,其底層實現直接映射到系統註冊表,使得 Java 應用能夠無需 JNI/JNA 即可讀寫註冊表。本文將通過完整示例,演示如何利用 Preferences API 實現註冊表的增刪改查與 XML 導出。
HKEY_CURRENT_USER\Software\JavaSoft\Prefs\test1\test1sub1。String、int、long、boolean、float、double、byte[] 七種類型。userRoot()(用戶級,HKCU)與 systemRoot()(系統級,HKLM,需管理員權限)。import java.io.FileOutputStream;
import java.io.IOException;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
public class RegistryDemo {
private static final String NODE_PATH = "com/myapp/config";
public static void main(String[] args) {
// 1. 獲取用戶級節點(自動創建)
Preferences prefs = Preferences.userRoot().node(NODE_PATH);
// 2. 寫入多類型數據
putPreferences(prefs);
// 3. 讀取並驗證
readPreferences(prefs);
// 4. 導出為 XML(備份/遷移)
exportToXml(prefs, "registry-backup.xml");
// 5. 清理演示:刪除整個節點樹
// deleteNodeTree(prefs); // 謹慎啟用
}
private static void putPreferences(Preferences prefs) {
prefs.put("db.url", "jdbc:mysql://localhost:3306/mydb");
prefs.putInt("db.pool.size", 20);
prefs.putLong("last.sync.time", System.currentTimeMillis());
prefs.putBoolean("auto.update", true);
prefs.putDouble("threshold", 0.85);
prefs.putFloat("ratio", 1.5f);
try {
prefs.putByteArray("license.key", "ABC-123-XYZ".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("✅ 寫入完成");
}
private static void readPreferences(Preferences prefs) {
String url = prefs.get("db.url", "默認值");
int poolSize = prefs.getInt("db.pool.size", 10);
long lastSync = prefs.getLong("last.sync.time", 0L);
boolean autoUpdate = prefs.getBoolean("auto.update", false);
double threshold = prefs.getDouble("threshold", 0.5);
float ratio = prefs.getFloat("ratio", 1.0f);
byte[] license = prefs.getByteArray("license.key", new byte[0]);
System.out.println("📖 讀取結果:");
System.out.printf(" db.url = %s%n", url);
System.out.printf(" db.pool.size = %d%n", poolSize);
System.out.printf(" last.sync.time = %d%n", lastSync);
System.out.printf(" auto.update = %b%n", autoUpdate);
System.out.printf(" threshold = %.2f%n", threshold);
System.out.printf(" ratio = %.1f%n", ratio);
System.out.printf(" license.key = %s%n", new String(license));
}
private static void exportToXml(Preferences prefs, String fileName) {
try (FileOutputStream fos = new FileOutputStream(fileName)) {
prefs.exportNode(fos); // 僅導出當前節點
// prefs.exportSubtree(fos); // 導出整棵子樹
System.out.println("📤 XML 導出成功: " + fileName);
} catch (IOException | BackingStoreException e) {
System.err.println("導出失敗: " + e.getMessage());
}
}
private static void deleteNodeTree(Preferences prefs) {
try {
prefs.removeNode(); // 遞歸刪除當前節點及所有子節點
System.out.println("🗑️ 節點樹已刪除");
} catch (BackingStoreException e) {
System.err.println("刪除失敗: " + e.getMessage());
}
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE preferences SYSTEM "https://java.sun.com/dtd/preferences.dtd">
<preferences EXTERNAL_XML_VERSION="1.0">
<root type="user">
<map/>
<node name="com">
<node name="myapp">
<node name="config">
<map>
<entry key="db.url" value="jdbc:mysql://localhost:3306/mydb"/>
<entry key="db.pool.size" value="20"/>
<entry key="last.sync.time" value="1702531200000"/>
<entry key="auto.update" value="true"/>
<entry key="threshold" value="0.85"/>
<entry key="ratio" value="1.5"/>
<entry key="license.key" value="QVJDLTEyMy1YWVo="/> <!-- Base64 編碼 -->
</map>
</node>
</node>
</node>
</root>
</preferences>
prefs.addPreferenceChangeListener(evt ->
System.out.printf("鍵 '%s' 變更: %s → %s%n", evt.getKey(), evt.getOldValue(), evt.getNewValue()));
prefs.addNodeChangeListener(evt ->
System.out.println("子節點 " + (evt.getChildAdded() ? "新增" : "移除") + ": " + evt.getChild().name()));
Preferences 修改默認異步刷新,關鍵配置需調用 prefs.flush() 強制持久化(會拋出 BackingStoreException)。
Preferences sysPrefs = Preferences.systemRoot().node("com/myapp/global");
// 寫入失敗將拋出 SecurityException 或 BackingStoreException
註冊表非為大數據設計,單值建議 < 4KB,總節點數勿過萬。大數據請改用文件/數據庫,註冊表僅存路徑引用。
HKCU\Software\JavaSoft\Prefs\...~/.java/.userPrefs/...(隱藏文件目錄)代碼無需修改即可跨平台運行,但備份/遷移時需注意路徑差異。
Preferences API 雖功能受限(無事務、無查詢、類型固定),但勝在零依賴、標準庫內置、跨平台透明。對於「應用配置、用戶偏好、少量狀態持久化」等輕量級場景,它是比屬性文件更強大、比數據庫更輕量的最佳選擇。掌握其節點樹模型與類型映射,即可輕松駕馭 Java 操作 Windows 註冊表的各類需求。