Java字符丢失与中文编码

编码|中文

1. 引言
在用JAVA进行开发时,偶尔在IO操作中会产生字符丢失现象。如在用BEA的WORKSHOP开发CMP EJB过程中,总是编译不通过,报错:

cannot resolve symbol

symbol : class Excetion

location: class eaitest.vip.firmorder.FirmOrderBean_g8ghds__WebLogic_CMP_RDBMS

} catch (Excetion ex) {

可以看到明显“Excetion”拼写错误。而这段代码是WORKSHOP自动生成。但是,在某些机器上,同样的工程文件,编译就能通过。联系BEA工程师,也不能解决此问题。

笔者查阅大量资料,很难找到相关问题的介绍。一次在偶尔查阅SUN的缺陷库[i]时,发现是由于GB18030中文编码问题所致。

2. 问题分析
国家标准GB18030-2000《信息交换用汉字编码字符集基本集的扩充》是我国继GB2312-1980和GB13000-1993之后最重要的汉字编码标准,是我国计算机系统必须遵循的基础性标准之一。国家质监总局规定GB 18030过渡期(即2001年8月31日)后正式发布或出厂的产品,必须符合GB-18030相关要求。

操作系统默认内部编码一般并不是GB18030,目前已知在WINDOWS XP操作系统中,进行某些组件的升级后,会把操作系统的默认编码由GB2312变更为GB18030。

但是即便在最新发布的JDK1.4.2_06版本中,对其支持仍存在一定问题。GB18030问题主要表现是,基于java的应用,涉及GB18030编码与其它编码方案转换时,存在字符丢失现象。

问题的原因是java在处理由sun.nio.cs.ext.ExtendedCharsets提供的扩展字符集时,会进行字符缓冲。但是对于缓冲字符没有采用新的sun.nio.cs.ext包处理,而是延用原有处理方式,这种方式在多线程操作下对GB18030编码方案处理存在问题,这样导致部分字符丢失。

此问题只影响GB18030编码方案,对GB2312等中文编码方案并没有影响。

当操作系统默认编码方案为GB18030时,如果进行文件写操作,未指定编码方案情况下,java采用操作系统默认编码方案操作,这时最容易出现GB18030问题。

查看操作系统默认编码,可以运行如下java程序:

public class EchoDefaultSystemEncoding{

public static void main(String[] args){

String encoding=System.getProperty(“file.encoding”);

System.out.println(“Default System Encoding: ” + encoding);

}

}

在用WORKSHOP开发CMP EJB出现问题的操作系统默认编码即为GB18030。

由于遇到此问题的人比较少。而真正遇到时,很多人通过重新安装操作系统可以解决问题,因而这方面的资料很难找到。

3. 解决办法
最理想的解决办法就是由SUN修正此BUG。此问题早在2003年11月即提出,但是直到目前(2004/12/30),问题状态仍为“In process, bug”。

替代的解决方案主要思路是避开GB18030编码,主要有两种方法

改变操作系统默认编码方案

对于unix/linux平台,修改操作系统编码方案很简单。如在solaris平台下,运行如下命令即可改变系统编码:

LANG=zh.GBK;export LANG

对于windows平台,修改操作系统中文默认编码比较复杂。尝试把操作系统的“区域和语言选项”更改为其它地区,选用其它语言,都没有效果。与微软客户服务联系,也不能提供相应解决方案。

运行java应用时指定默认编码

在运行基于JAVA的应用时,加上参数:

java –Dfile.encoding=GB2312

把java应用的默认编码方案与GB2312硬绑定,即在未指明编码方案时,采用GB2312编码。

如果针对每个应用,进行上述修改,工作量很大。有些应用里面又隐式调用外部JAVA应用,更增加修正的难度。比较可行的办法是对java的运行文件进行修正,令其在运行时自动加上“-Dfile.encoding=GB2312”参数。

建议windows平台采用本方法进行修正。方案如下:

1、改名原java.exe,javaw.exe,如改为javabak.exe,javawbak.exe

2、重写java.exe和javaw.exe,令其运行时调用javabak.exe,javawbak.exe,并在运行时加上“-Dfile.encoding”参数。

如下c代码即可完成上述功能:

#include "string.h"

#include "stdlib.h"

int main(int argc, char* argv[])

{

char arg[100000] = "javabak.exe -Dfile.encoding=GB2312 ";

for(int i=1; i<argc; i++){

strcat(arg,argv[i]);

strcat(arg, " ");

}

system(arg);

return 0;

}

编译后(注意修改arg值),生成的文件命名为java.exe和javaw.exe,放置在<JAVA_HOME>/bin和<JAVA_HOME>/jre/bin目录下,即可。

经实践,此办法可以解决GB18030问题,并且不会带来其它隐患。唯一的缺点是在运行JAVA应用时,会有一个额外的DOS窗口打开,此窗口可以关闭,不会对应用运行带来影响。

4. 总结
在应用开发中,中文编码一直是一个比较麻烦的问题。尽管目前GB18030是国家强制性标准,有着各种各样的优点,但由于其推出时间尚短,在应用方面对其支持还不够完善,还是应尽可能采用GB2312等兼容性比较强的中文编码方案。

本文给出的解决方案,不仅适用于解决JAVA平台对GB18030支持问题,而且,也为指定通用JAVA运行默认参数,提供了另一种思路。

时间: 2024-11-17 15:07:52

Java字符丢失与中文编码的相关文章

java字符流处理之while readline

BufferedReader的readLine()方法是阻塞式的, 如果到达流末尾, 就返回null, 但如果client的socket末经关闭就销毁, 则会产生IO异常. 正常的方法就是使用socket.close()关闭不需要的socket. 从一个有若干行的文件中依次读取各行,处理后输出,如果用以下方法,则会出现除第一行外行首字符丢失现象 String str  = null;br=new BufferedReader(new FileReader(fileName));do{  str

我的Java开发学习之旅------&amp;gt;Java字符编码解析

Java开发中,常常会遇到乱码的问题,一旦遇到这种问题,常常就很扯蛋,每个人都不愿意承认是自己的代码有问题.其实编码问题并没有那么神秘,那么不可捉摸,搞清Java的编码本质过程就真相大白了.               其实,编码问题存在两个方面:JVM之内和JVM之外.   1.Java文件编译后形成class 这里Java文件的编码可能有多种多样,但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UT

java字符转换成数字问题?不懂什么意思c=&amp;amp;#39;6&amp;amp;#39;;int a = c-&amp;amp;#39;0&amp;amp;#39;;

问题描述 java字符转换成数字问题?不懂什么意思c='6';int a = c-'0'; 字符转换成数字问题?不懂什么意思 c='6'; int a = c-'0'; 那个-'0'表示什么意思呢??百度了下好像是什么js的弱类型转换?帮忙解释下谢谢了 解决方案 c的类型很关键你却没给出来! 先说int型,可以把你那个代码转换一下 int c='6'; int x='0'; int a=c-x; //System.out.println("c:"+c);//54 //System.ou

java 字符替换问题。。。。

问题描述 java 字符替换问题.... http://192.168.1.254record2015Y04M03D14H19M00S.mp4?custom=1&cmd=4001怎么把里面的 替换换成 / ? 解决方案 String str = ""http://192.168.1.254\record\2015Y04M03D14H\19M00S.mp4?custom=1&cmd=4001""; String newStr = str.replace

Java字符流与字节流区别与用法分析_java

本文实例讲述了Java字符流与字节流区别与用法.分享给大家供大家参考,具体如下: 字节流与字符流主要的区别是他们的的处理方式 流分类: 1.Java的字节流 InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先. 2.Java的字符流 Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先. InputStream,OutputStream,Reader,writer都是抽象类.所以不能直接new 字节流是最基本的,所有的Inpu

Java 字符终端上获取输入三种的方式分享_java

在Java 字符终端上获取输入有三种方式: 1.java.lang.System.in (目前JDK版本均支持)2.java.util.Scanner (JDK版本>=1.5)3.java.io.Console(JDK版本>=1.6),特色:能不回显密码字符 参考:这里记录Java中从控制台读入信息的几种方式(1)JDK 1.4(JDK 1.5和JDK 1.6也都兼容这种方法) 复制代码 代码如下: public class TestConsole1 {      public static

Java字符流和字节流对文件操作的区别_java

记得当初自己刚开始学习Java的时候,对Java的IO流这一块特别不明白,所以写了这篇随笔希望能对刚开始学习Java的人有所帮助,也方便以后自己查询.Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,然后再输出到另一个文件中.而字符流操作的最小单位则是字符.可以先看一下IO流的概述:   下面首先是通过字符流对文件进行读取和写入: package lib; import jav

java字符替换三个简单实例

java字符替换,在java中进行字符替换我们也可以用到replace函数,下面来看看三个实例的方法. public class MainClass {    public static void main( String args[] )    {       String s1 = new String( "hello" );       String s2 = new String( "GOODBYE" );       String s3 = new Str

Java字符编码转换过程说明

Java字符编码转换过程说明 />/> 常见问题 JVM JVM启动后,JVM会设置一些系统属性以表明JVM的缺省区域. user.language,user.region,file.encoding等. 可以使用System.getProperties()详细查看所有的系统属性. 如在英文操作系统(如UNIX)下,可以使用如下属性定义强制指定JVM为中文环境 -Dclient.encoding.override=GBK -Dfile.encoding=GBK -Duser.language=