程式扎記: [ Java 文章收集 ] Java 對 機碼的操作

標籤

2011年7月14日 星期四

[ Java 文章收集 ] Java 對 機碼的操作

轉載自 這裡 
前言 : 
- 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是一個抽像類,提供了一系列靜態方法和抽像方法來操作參數項. 抽像方法如下 : 

  1. Preferences userData = Preferences.userNodeForPackage(this);  
  2. Preferences sysData = Preferences.systemNodeForPackage(this);  
這兩個方法是從指定的物件所在的包(package)返回一個節點路徑,如this是javax.swing.JComponent, 則返回/javax/swing. 靜態方法如下 : 
  1. Preferences userData = Preferences.userRoot().node("/com/sunway/spc");  
  2. 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 :
  1. package test;  
  2.   
  3. import java.io.*;  
  4. import java.util.prefs.*;  
  5.   
  6. public class PrefsDemo {  
  7.     public static void main(String args[]) {  
  8.         String keys[] = { "sunway""copyright""author" };  
  9.         String values[] = { "sunway technology company""copyright 2002",  
  10.                 "turbochen@163.com" };  
  11.   
  12.         /* 建立一個位於user root下的/com/sunway/spc節點參數項 */  
  13.         Preferences prefsdemo = Preferences.userRoot().node("/com/sunway/spc");  
  14.   
  15.         /* 儲存參數項 */  
  16.         for (int i = 0; i < keys.length; i++) {  
  17.             prefsdemo.put(keys[i], values[i]);  
  18.         }  
  19.   
  20.         /* 導出到XML文件 */  
  21.         try {  
  22.             FileOutputStream fos = new FileOutputStream("prefsdemo.xml");  
  23.             prefsdemo.exportNode(fos);  
  24.         } catch (Exception e) {  
  25.             System.err.println("Cannot export nodes: " + e);  
  26.         }  
  27.   
  28.         /* 去掉註釋可以清除註冊表中的參數項 */  
  29.         /* 
  30.          * try { prefsdemo.removeNode(); } catch (BackingStoreException e) { } 
  31.          */  
  32.   
  33.     }  
  34. }  

執行結果 : 
[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 :
  1. package test;  
  2.   
  3. import com.ice.jni.registry.NoSuchKeyException;    
  4. import com.ice.jni.registry.RegStringValue;    
  5. import com.ice.jni.registry.Registry;    
  6. import com.ice.jni.registry.RegistryException;    
  7. import com.ice.jni.registry.RegistryKey;   
  8.   
  9. public class JNIRegistryTest {  
  10.     public static void main(String args[])  
  11.     {  
  12.         String sKeyNameStr = "SubKeyName";  
  13.         String sKeyStrKey1 = "subKey1";  
  14.         String sKeyStrKey2 = "subKey2";  
  15.           
  16.         //創建註冊表並設置相應的值    
  17.            try {    
  18.              RegistryKey software = Registry.HKEY_LOCAL_MACHINE    
  19.                .openSubKey("SOFTWARE");    
  20.              RegistryKey subKey = software.createSubKey(sKeyNameStr, "");    
  21.              subKey.setValue(new RegStringValue(subKey, sKeyStrKey1,    
  22.                "subKey1Value"));    
  23.              subKey.setValue(new RegStringValue(subKey, sKeyStrKey2,    
  24.                "subKey2Value"));    
  25.              subKey.closeKey();    
  26.            } catch (NoSuchKeyException e) {    
  27.              e.printStackTrace();    
  28.            } catch (RegistryException e) {    
  29.              e.printStackTrace();    
  30.            }  
  31.              
  32.          //打開註冊表項並讀出相應的值    
  33.            try {    
  34.              RegistryKey software = Registry.HKEY_LOCAL_MACHINE.    
  35.                openSubKey("SOFTWARE");    
  36.              RegistryKey subKey = software.openSubKey(sKeyNameStr);    
  37.              String subKey1Value = subKey.getStringValue(sKeyStrKey1);    
  38.              String subKey2Value = subKey.getStringValue(sKeyStrKey2);    
  39.              System.out.println(subKey1Value);    
  40.              System.out.println(subKey2Value);    
  41.              subKey.closeKey();    
  42.            } catch (NoSuchKeyException e) {    
  43.              e.printStackTrace();    
  44.            } catch (RegistryException e) {    
  45.              e.printStackTrace();    
  46.            }  
  47.     }  
  48. }  

執行結果 : 
結果會在機碼路徑如下新增 Key/Value pair : 
[HKEY_LOCAL_MACHINE\SOFTWARE\SubKeyName]
"subKey1"="subKey1Value"
"subKey2"="subKey2Value"

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!