您的位置:首页 > 编程语言 > Java开发

关于JNI 和JAVA 编码的问题小结

2008-12-16 10:50 288 查看
关于JNI 和JAVA 编码的问题小结

好久不写博客,最近发生了好多的事情,但是我还是希望精诚所至金石为开,能让我有个很美好的结局。最近在研究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/ prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1.4.2/docs/guide/jni/index.html
标签: