註冊表包含 Windows 在運行期間不斷引用的資訊,例如,每個使用者的設定檔、電腦上安裝的應用程式以及每個應用程式可以建立的文件類型、檔案夾和應用程式圖示的屬性工作表設定、系統上存在哪些硬體以及正在使用哪些連接埠。
註冊表取代了 Windows 3.x 和 MS-DOS 設定檔(例如,Autoexec.bat 和 Config.sys)中使用的絕大多數基於文本的 .ini 檔案。雖然幾個 Windows 作業系統都有註冊表,但這些作業系統的註冊表有一些區別。
如果您對以上的內容還不瞭解,那麼您可能需要閱讀一下這篇文章《Microsoft Windows 註冊表說明》,可以從參考資料中找到,同時還可以找到它的英文原文"Description of the Microsoft Windows registry"。
如果您理解上面的內容就可以往下繼續了。
使用Preferences API
Preferences API並不是為訪問Windows註冊表而設計的,這是值得指出的一點。
我們之所以會有上面的誤解是由於Sun的Windows版本的JDK在實現Preferences API時使用了Windows註冊表作為存放庫,即我們用Preferences API儲存的資料會儲存到Windows註冊表中,這樣Preferenes API也就有了訪問Windows註冊表的能力。但是換到其它的平台或其它廠商的JDK實現又會怎麼樣呢?這個問題是和Preferences API的實現相關的,我們沒有辦法回答。
如果程式不關心存放庫的細節,只是要找一個存放資料的地方,那麼Preferences API很合適。
Preferences API也是有局限的,請您考慮兩個問題:
- 一個Java軟體,這次我在Sun的JDK上運行並使用Preferences API儲存了我的個人喜好,下次我在IBM的JDK上運行,這時我的個人喜好還可以通過Preferences API得到嗎?可能可以也可能不可以,這時的行為是由Sun和IBM的Preferences API實現決定的。(在相同的JDK實現上可以使用Preferences API來在不同的程式間共用資料)
- 一個Java軟體需要讓使用者佈建是否和作業系統一起啟動,類似的需求還很多。這類需求就是要求Java程式有真正的和相關作業系統協同的能力。這種能力不是Preferences API的設計目標。
如果您對Preferences API還不瞭解,那麼您可能需要閱讀一下這篇文章《用Preferences API儲存物件》,可以從參考資料中找到。
使用JNI
Windows作業系統提供了操作註冊表的API,因此用JNI將Java和這些API串連起來我們就獲得了用Java操作註冊表的能力。這說起來有些簡單,實現起來卻需要處理大量的細節。幸運的是這樣的工作已經有人做了,我們要感謝他們。下面我們就來看看其中的一個包。
com.ice.jni.registry包是通過JNI(Java native interface)實現的Windows註冊表操作API,可以用來訪問、修改和匯出Windows註冊表。現在這個包已經公開了,可以放心的使用而不必擔心license的問題,並且包括一個構建好的DLL和Java、C的原始碼。它可以在Java 1.1和更高的版本上工作。
如果您向我一樣也對JNI感興趣,那麼這也是學習JNI的很好的樣本。
下面詳細的描述一下這個包中的類,數量不是很多:
- HexNumberFormat 用來格式化和分析十六進位整數。
- RegBinaryValue 表示類型為REG_BINARY的註冊表值。REG_BINARY是指任意形式的位元。
- RegDWordValue 表示類型為REG_DWORD的註冊表值。REG_DWORD是指一個32位的整數。根據該整數的位元組序不同又分為REG_DWORD_LITTLE_ENDIAN和REG_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)和相關的一些操作。
如果您需要瞭解更多的細節,請查閱參考資料中的JNIRegistry的Java doc、Registry和Registry Reference。
RegistryKey的方法概要:
| 方法 |
簡短描述 |
| void closeKey() |
關閉該subkey。 |
| RegistryKey connectRegistry(java.lang.String hostName) |
串連遠程主機hostName的註冊表。 |
| RegistryKey createSubKey(java.lang.String subkey, java.lang.String className) |
建立和開啟該key的subkey,具有寫入權限。 |
| RegistryKey createSubKey(java.lang.String subKey, java.lang.String className, int access) |
建立和開啟該key的subkey,具有指定的許可權。 |
| int decrDoubleWord(java.lang.String valueName) |
該方法將消減REG_DWORD的值。 |
| void deleteSubKey(java.lang.String subKey) |
刪除該subkey。 |
| void deleteValue(java.lang.String valueName) |
刪除一個命名的值。 |
| static java.lang.String expandEnvStrings(java.lang.String exString) |
展開exString中的環境變數。 |
| void export(java.io.PrintWriter out, boolean descend) |
匯出key。 |
| void finalize() |
重載了的finalize()方法,確保能夠關閉key。 |
| void flushKey() |
確保這個key被寫到磁碟,對效能有一定的影響。 |
| java.lang.String getDefaultValue() |
得到該key的預設值。 |
| java.lang.String getFullName() |
得到key的全名。 |
| int getMaxSubkeyLength() |
得到所有subkey名稱的最大長度。 |
| int getMaxValueDataLength() |
得到所有subkey值的最大長度。 |
| int getMaxValueNameLength() |
得到所有值的名稱的最大長度。 |
| java.lang.String getName() |
得到該key的名稱。 |
| int getNumberSubkeys() |
得到subkey的數量。 |
| int getNumberValues() |
得到值的數量。 |
| java.lang.String getStringValue(java.lang.String valueName) |
得到REG_SZ或REG_EXPAND_SZ的值。 |
| RegistryValue getValue(java.lang.String valueName) |
得到valueName的值。 |
| boolean hasDefaultValue() |
判斷該key是否有預設值。 |
| boolean hasOnlyDefaultValue() |
判斷該key是否只有預設值。 |
| int incrDoubleWord(java.lang.String valueName) |
該方法將增強REG_DWORD的值。 |
| java.util.Enumeration keyElements() |
枚舉該key的subkey的名稱。 |
| RegistryKey openSubKey(java.lang.String subkey) |
開啟該key的subkey,具有寫入權限。 |
| RegistryKey openSubKey(java.lang.String subKey, int access) |
開啟該key的subkey,具有指定的許可權。 |
| java.lang.String regEnumKey(int index) |
得到該key在index處的subkey。 |
| java.lang.String regEnumValue(int index) |
得到該key在index處的subkey的值。 |
| void setCreated(boolean created) |
設定該key的created狀態。 |
| void setValue(RegistryValue value) |
設定該key的值。 |
| void setValue(java.lang.String valueName, RegistryValue value) |
設定valueName的值。 |
| java.util.Enumeration valueElements() |
枚舉該key的值的名稱。 |
| boolean wasCreated() |
判斷該key是被opened還是被created和opened。 |
最後我們來看一個程式碼範例:
package org.solol.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;/** * @author solo L * */public class JNIRegistryTest { /** * @param args */ public static void main(String[] args) { //建立登錄機碼並設定相應的值 try { RegistryKey software = Registry.HKEY_LOCAL_MACHINE .openSubKey("SOFTWARE"); RegistryKey subKey = software.createSubKey("SubKeyName", ""); subKey.setValue(new RegStringValue(subKey, "subKey1", "subKey1Value")); subKey.setValue(new RegStringValue(subKey, "subKey2", "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("SubKeyName"); String subKey1Value = subKey.getStringValue("subKey1"); String subKey2Value = subKey.getStringValue("subKey2"); System.out.println(subKey1Value); System.out.println(subKey2Value); subKey.closeKey(); } catch (NoSuchKeyException e) { e.printStackTrace(); } catch (RegistryException e) { e.printStackTrace(); } }}
建立的登錄機碼:
輸出結果為:
subKey1Value
subKey2Value
參考資料
- 用Preferences API儲存物件,這是一篇來自IBM的文章可以使您進一步瞭解Preferences API。
- Microsoft Windows 註冊表說明
- Description of the Microsoft Windows registry
- 在JNIRegistry這裡可以下載到需要的包和原始碼。
- 如果您想閱讀JNIRegistry的Java doc可以來這裡。
- 在Registry和Registry Reference可以找到關於註冊表、註冊表函數、註冊表結構、註冊表元素大小限制和註冊表實值型別等大量的資訊。
說明:我的體會“第一步:把下載下來的jar包載入到工程內,第二步,把與jar包在一起的dll檔案拷貝到你jdk安裝目錄下/jre/bin檔案夾下”