關於JNI 和JAVA 編碼的問題小結<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
好久不寫博客,最近發生了好多的事情,但是我還是希望精誠所至金石爲開,能讓我有個很美好的結局。最近在研究Java和C之間的通過JNI進行調用的問題,所以今天總結一下存檔,也方便以後翻出來重讀。
總的來說呢,都是關於編碼的問題,具體的問題如下:在Linux下,寫了簡單的c 來調用java,這樣的程式很多,大家也可以看/jdk/src/java.c,也是個很好的例子。我的情況如下,在call 完java的程式之後,發現下面的語句執行失敗:
Int itmp;
Itmp = sprintf(s,”%s”,str);
其中str爲big5的編碼“測試程式”, 執行完後s爲空,itmp = -1;
Os: en_US.UTF-8,
然後就查找sprintf的msdn:
The number of characters written, or –1 if an error occurred. If buffer or format is a null pointer, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, these functions return -1 and set errno to EINVAL.
所以添加如下代碼來排錯:
Char *s;
S = setlocale(LC_CTYPE,(char *)NULL);
S = setlocale(LC_ALL,(char*)NULL);
查看調用java和不調用java的區別:如果不調用java,那麼LC_CTYPE爲”C”,如果調用java,那麼LC_CTYPE=en_US.UTF-8
哦,原來是JNI_CreateJavaVM 調用之後,修改了LC_CTYPE的值。
所以問題的本質就產生了:當os的編碼設置和自己程序中的編碼不一致的時候,應該怎麼辦??
當然很多人都會說:修改環境變量LANG的值 LANG=zh_TW,或者修改LC_CTYPE=zh_TW,但是有些情況,我們不希望爲了執行我們自己的程序而修改整個的環境變量。
當然如果能夠在啓動JVM的時候指定編碼就好了,可是我在JavaVMInitArgs嘗試添加user.language=zh user.region=CN sun.jnu.encoding=GBK,仍然不起任何作用,LC_CTYPE依然爲en_US.UTF-8,看樣子這種客戶端版本的jre就是和os相關,不能手工設置,當然一些server版的可以自己設置。
目前我們想到的解決的辦法是call 完 java之後,調用setlocale將值設回之前的值。目前不知道這種解決的辦法是否會引起錯誤。
我看了一些網上的說法:
.java可以是任意的編碼。
通過javac編譯的時候可以指定編碼例如: javac –encoding 來指定編碼。比如javac -encoding big5 abc.java 或者javac -encoding gb2312 abc.java
由於JDK是國際版的,在編譯的時候,如果我們沒有用-encoding參數指定我們的JAVA源程序的編碼格式,則javac.exe首先獲得我們操作系統默認採用的編碼格式,也即在編譯java程序時,若我們不指定源程序文件的編碼格式,JDK首先獲得操作系統的file.encoding參數(它保存的就是操作系統默認的編碼格式,如WIN2k,它的值爲GBK),然後JDK就把我們的java源程序從file.encoding編碼格式轉化爲JAVA內部默認的UNICODE格式放入內存中。然後,javac把轉換後的unicode格式的文件進行編譯成.class類文件,此時.class文件是UNICODE編碼的,它暫放在內存中,緊接着,JDK將此以UNICODE編碼的編譯後的class文件保存到我們的操作系統中形成我們見到的.class文件。對我們來說,我們最終獲得的.class文件是內容以UNICODE編碼格式保存的類文件,它內部包含我們源程序中的中文字符串,只不過此時它己經由file.encoding格式轉化爲UNICODE格式。
我在網上看到一些帖子中說 .class 文件是UTF-8的格式,我猜想是因爲UCS-2有LITTLE ENDIAN 和BIG endian的區別,所以不能夠完全的跨平臺,而UTF-8則是完全的跨平臺。
通過java來解釋執行.class文件,其實就是通過C來啓動JVM來解釋執行,就是通過UCS-2來進行通信,最後的結果由於要在OS上顯示,所以需要將UCS-2轉換爲LOCALE來顯示在OS上。
也不知道我的理解是否正確。O(∩_∩)O哈哈~
如果想要學習JNI,可以在這個網址上找到一些有用的信息:
http://java.sun.com/j2se/1.4.2/docs/guide/jni/jni-12.html
http://java.sun.com/j2se/<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1.4.2/docs/guide/jni/index.html