轉載自 這裡
前言 :
- Preferences的誤解
首先要指明的是 Preferences API 並不是為訪問Windows註冊表而設計的. 我們之所以會有Preferences API 是用來操作機碼的誤解是由於Sun的Windows版本的JDK在實現Preferences API時使用了Windows註冊表作為存儲庫. 即我們用Preferences API存儲的數據會保存到Windows註冊表中,這樣Preferenes API也就有了訪問Windows註冊表的能力. 但是換到其它的平台或其它廠商的JDK實現又會怎麼樣呢? 這個問題是和Preferences API的實現相關的並沒有固定答案.
- Preferences適用的條件
如果程序不關心存儲庫的細節,只是要找一個存放數據的地方,那麼Preferences API很合適.
- Preferences API的局限
一個Java軟件,這次我在Sun的JDK上運行並使用Preferences API保存了我的個人喜好,下次我在IBM的JDK上運行,這時我的個人喜好還可以通過Preferences API得到嗎? 可能可以也可能不可以,這時的行為是由Sun和IBM的Preferences API實現決定的.(在相同的JDK實現上可以使用Preferences API來在不同的程序間共享數據)
使用 Preferences : (Preferences API Guide, Online API)
我們經常需要將我們的程序中的設定,如窗口位置,開啟過的文件,用戶的選項設定等數據記錄下來,以做便用戶下一次開啟程序能繼續使用這些數據. Java的Preferences類提供了類似的機制. Preferences類在不同的平台中有不同的實現方式。而在Windows平台中,Preferences是將數據保存在註冊表中的.
- 建立Preferences對像
為了區分不同的應用程序的參數項,在建立Preferences時要指定一個節點路徑. Preferences是一個抽像類,提供了一系列靜態方法和抽像方法來操作參數項. 抽像方法如下 :
- Preferences userData = Preferences.userNodeForPackage(this);
- Preferences sysData = Preferences.systemNodeForPackage(this);
這兩個方法是從指定的物件所在的包(package)返回一個節點路徑,如this是javax.swing.JComponent, 則返回/javax/swing. 靜態方法如下 :
- Preferences userData = Preferences.userRoot().node("/com/sunway/spc");
- Preferences sysData = Preferences.systemRoot().node("/com/sunway/spc");
以上每種方式提供了兩套操作方法。其中一套是用戶參數項,另一套是系統參數項. 在Windows平台中,用戶參數項在註冊表中的根節點是 :
HKEY_CURRENT_USER\Software\JavaSoft\Prefs
系統參數項在註冊表中的根節點是 :
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs
而我們指定的節點路徑是位於這些根節點之下的.
- 讀寫數據
Preferences提供了多種類型數據的讀寫方法. 先來看寫(put)的方法 :
put(String key, String value)
putBoolean(String key, boolean value)
putByteArray(String key, byte value[])
putDouble(String key, double value)
putFloat(String key, float value)
putInt(String key, int value)
putLong(String key, long value)
下面的是讀(get)的方法 :
get(String key, String default)
getBoolean(String key, boolean default)
getByteArray(String key, byte default[])
getDouble(String key, double default)
getFloat(String key, float default)
getInt(String key, int default)
getLong(String key, long default)
注意,每一種get方法的第二個參數需要我們為它指定缺省的參數. 除了以上方式之外,Preferences還允許我們將它的數據導出到一個XML文件保存 :
void exportNode(OutputStream os)
void exportSubtree(OutputStream os)
我們可以導出一個節點,或是導出整個子節點樹.
- Preferences的一個演示
以上的講解足可以寫一個示例來看看Preferences是如何為我們工作的,看看下面的例子 :
- PrefsDemo.java :
- package test;
-
- import java.io.*;
- import java.util.prefs.*;
-
- public class PrefsDemo {
- public static void main(String args[]) {
- String keys[] = { "sunway", "copyright", "author" };
- String values[] = { "sunway technology company", "copyright 2002",
- "turbochen@163.com" };
-
-
- Preferences prefsdemo = Preferences.userRoot().node("/com/sunway/spc");
-
-
- for (int i = 0; i < keys.length; i++) {
- prefsdemo.put(keys[i], values[i]);
- }
-
-
- try {
- FileOutputStream fos = new FileOutputStream("prefsdemo.xml");
- prefsdemo.exportNode(fos);
- } catch (Exception e) {
- System.err.println("Cannot export nodes: " + e);
- }
-
-
-
-
-
-
- }
- }
執行結果 :
[HKEY_CURRENT_USER\Software\JavaSoft\Prefs\com\sunway\spc]
"sunway"="sunway technology company"
"copyright"="copyright 2002"
"author"="turbochen@163.com"
使用JNI 操作機碼 :
Windows操作系統提供了操作註冊表的API,因此用JNI將Java和這些API連接起來我們就獲得了用Java操作註冊表的能力. 這說起來有些簡單,實現起來卻需要處理大量的細節。幸運的是這樣的工作已經有人做了,我們要感謝他們. 下面我們就來看看其中的一個包.
- com.ice.jni.registry (下載, Online API)
這個 Package 是通過 JNI (Java native interface)實現的Windows註冊表操作API,可以用來訪問、修改和導出Windows註冊表。現在這個包已經公開了,可以放心的使用而不必擔心license的問題,並且包括一個構建好的DLL和Java、C的源代碼。它可以在Java 1.1和更高的版本上工作. 下面簡單介紹一下該 Package 的常見類別 :
* HexNumberFormat 用來格式化和分析十六進制整數。
* RegBinaryValue 表示類型為REG_BINARY的註冊表值。REG_BINARY是指任意形式的二進制數。
* RegDWordValue 表示類型為REG_DWORD的註冊表值。REG_DWORD是指一個32位的整數。根據該整數的字節序不同又分為REG_DWORD_LITTLE_ENDIANREG_DWORD_BIG_ENDIAN。在Windows中REG_DWORD和REG_DWORD_LITTLE_ENDIAN有相同的含義。
* RegistryValue 表示任意類型的註冊表值,這是一個抽像類,不能被實例化。
* RegMultiStringValue 表示類型為REG_MULTI_SZ的註冊表值。REG_MULTI_SZ是一個null-terminated的字符串的序列。
* RegStringValue 表示類型為REG_SZ和REG_EXPAND_SZ的註冊表值。REG_SZ是指一個null-terminated的字符串,REG_EXPAND_SZ是指一個含有未展開的環境變量的null-terminated的字符串。
* Registry 這個類定義了定級項(Key),包括HKEY_CLASSES_ROOT、HKEY_CURRENT_CONFIG、HKEY_CURRENT_USER、HKEY_DYN_DATA、HKEY_LOCAL_MACHINE、HKEY_PERFORMANCE_DATA和HKEY_USERS。還定義了錯誤代碼,這些錯誤代碼會包含在RegistryException中。最後是一些工具方法,如dumpHexData、exportRegistryKey、getErrorMessage、getTopLevelKey、openSubkey、parseArgumentString、parseArgumentVector、splitString和usage。
* RegistryKey 定義了註冊表的一個表項(Key)和相關的一些操作。
最後我們來看一個範例 :
- JNIRegistryTest.java :
- package test;
-
- import com.ice.jni.registry.NoSuchKeyException;
- import com.ice.jni.registry.RegStringValue;
- import com.ice.jni.registry.Registry;
- import com.ice.jni.registry.RegistryException;
- import com.ice.jni.registry.RegistryKey;
-
- public class JNIRegistryTest {
- public static void main(String args[])
- {
- String sKeyNameStr = "SubKeyName";
- String sKeyStrKey1 = "subKey1";
- String sKeyStrKey2 = "subKey2";
-
-
- try {
- RegistryKey software = Registry.HKEY_LOCAL_MACHINE
- .openSubKey("SOFTWARE");
- RegistryKey subKey = software.createSubKey(sKeyNameStr, "");
- subKey.setValue(new RegStringValue(subKey, sKeyStrKey1,
- "subKey1Value"));
- subKey.setValue(new RegStringValue(subKey, sKeyStrKey2,
- "subKey2Value"));
- subKey.closeKey();
- } catch (NoSuchKeyException e) {
- e.printStackTrace();
- } catch (RegistryException e) {
- e.printStackTrace();
- }
-
-
- try {
- RegistryKey software = Registry.HKEY_LOCAL_MACHINE.
- openSubKey("SOFTWARE");
- RegistryKey subKey = software.openSubKey(sKeyNameStr);
- String subKey1Value = subKey.getStringValue(sKeyStrKey1);
- String subKey2Value = subKey.getStringValue(sKeyStrKey2);
- System.out.println(subKey1Value);
- System.out.println(subKey2Value);
- subKey.closeKey();
- } catch (NoSuchKeyException e) {
- e.printStackTrace();
- } catch (RegistryException e) {
- e.printStackTrace();
- }
- }
- }
執行結果 :
結果會在機碼路徑如下新增 Key/Value pair :
[HKEY_LOCAL_MACHINE\SOFTWARE\SubKeyName]
"subKey1"="subKey1Value"
"subKey2"="subKey2Value"
沒有留言:
張貼留言