1. 程式人生 > >用Java操作Windows登錄檔

用Java操作Windows登錄檔

Microsoft Windows 9x、Windows CE、Windows NT和Windows 2000中使用的中央分層資料庫,用於儲存為一個或多個使用者、應用程式和硬體裝置配置系統所必需的資訊。

Microsoft Windows 9x、Windows CE、Windows NT和Windows 2000中使用的中央分層資料庫,用於儲存為一個或多個使用者、應用程式和硬體裝置配置系統所必需的資訊。

登錄檔包含 Windows 在執行期間不斷引用的資訊,例如,每個使用者的配置檔案、計算機上安裝的應用程式以及每個應用程式可以建立的文件型別、資料夾和應用程式圖示的屬性表設定、系統上存在哪些硬體以及正在使用哪些埠。

登錄檔取代了 Windows 3.x 和 MS-DOS 配置檔案(例如,Autoexec.bat 和 Config.sys)中使用的絕大多數基於文字的 .ini 檔案。雖然幾個 Windows 作業系統都有登錄檔,但這些作業系統的登錄檔有一些區別。

如果您對以上的內容還不瞭解,那麼您可能需要閱讀一下這篇文章《Microsoft Windows 登錄檔說明》,可以從參考資料中找到,同時還可以找到它的英文原文"Description of the Microsoft Windows registry"。

如果您理解上面的內容就可以往下繼續了。

回頁首

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