Java 中文问题的表层分析及处理(转)

本文探讨了Java应用程序中中文乱码的问题,详细介绍了如何通过字符编码转换解决从数据库读取和写入中文的问题,并提供了实用的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

.CLASS   文件存放在服务器端,由客户端的浏览器运行   APPLET   ,   APPLET   只起调入   FRAME   类等主程序的作用。界面包括   Textfield   ,TextArea,List,Choice   等。    
   
  I.  取中文    
   
  用   JDBC   执行   SELECT   语句从服务器端读取数据(中文)后,将数据用   APPEND   方法加到   TextArea(TA)   ,不能正确显示。但加到   List   中时,大部分汉字却可正确显示。    
   
  将数据按“ISO-8859-1”   编码方式转化为字节数组,再按系统缺省编码方式   (Default   Character   Encoding)   转化为   STRING   ,即可在   TA   和   List   中正确显示。    
   
  程序段如下:    
   
  dbstr2   =   results.getString(1);    
   
  //After   reading   the   result   from   DB   server,converting   it   to   string.    
   
  dbbyte1   =   dbstr2.getBytes(“iso-8859-1”);    
   
  dbstr1   =   new   String(dbbyte1);    
   
  在转换字符串时不采用系统默认编码方式,而直接采用“   GBK”   或者   “GB2312”   ,在   A   和   B   两种情况下,从数据库取数据都没有问题。    
   
  II.   写中文到数据库    
   
  处理方式与“取中文”相逆,先将   SQL   语句按系统缺省编码方式转化为字节数组,再按“ISO-8859-1”编码方式转化为   STRING   ,最后送去执行,则中文信息可正确写入数据库。    
   
  程序段如下:    
   
  sqlstmt   =   tf_input.getText();    
   
  //Before   sending   statement   to   DB   server,converting   it   to   sql   statement.    
   
  dbbyte1   =   sqlstmt.getBytes();    
   
  sqlstmt   =   newString(dbbyte1,”iso-8859-1”);    
   
  _stmt   =   _con.createStatement();    
   
  _stmt.executeUpdate(sqlstmt);    
   
  ……    
   
  问题:如果客户机上存在   CLASSPATH   指向   JDK   的   CLASSES.ZIP   时(称为   A   情况),上述程序代码可正确执行。但是如果客户机只有浏览器,而没有   JDK   和   CLASSPATH   时(称为   B   情况),则汉字无法正确转换。    
   
  我们的分析:    
   
  1.经过测试,在   A   情况下,程序运行时系统的缺省编码方式为   GBK   或者   GB2312   。在   B   情况下,程序启动时浏览器的   JAVA   控制台中出现如下错误信息:    
   
  Can't   find   resource   for   sun.awt.windows.awtLocalization_zh_CN    
   
  然后系统的缺省编码方式为“8859-1”。    
   
  2.如果在转换字符串时不采用系统缺省编码方式,而是直接采用   “GBK”   或“GB2312”,则在   A   情况下程序仍然可正常运行,在   B   情况下,系统出现错误:    
   
  UnsupportedEncodingException。    
   
  3.在客户机上,把   JDK   的   CLASSES.ZIP   解压后,放在另一个目录中,   CLASSPATH   只包含该目录。然后一边逐步删除该目录中的   .CLASS   文件,另一边运行测试程序,最后发现在一千多个   CLASS   文件中,只有一个是必不可少的,该文件是:    
   
  sun.io.CharToByteDoubleByte.class。    
   
  将该文件拷到服务器端和其它的类放在一起,并在程序的开头   IMPORT   它,在   B   情况下程序仍然无法正常运行。    
   
  4.在   A   情况下,如果在   CLASSPTH   中去掉   sun.io.CharToByteDoubleByte.class   ,则程序运行时测得默认编码方式为“8859-1”,否则为   “GBK”   或   “GB2312”   。    
   
  如果   JDK   的版本为1.2以上的话,在   B   情况下遇到的问题得到了很好的解决,测试的步骤同上,有兴趣的读者可以尝试一下。    
   
  Java   中文问题的根源分析及解决    
   
  在简体中文   MS   Windows   98   +   JDK   1.3   下,可以用   System.getProperties()   得到   Java   运行环境的一些基本属性,类   PoorChinese   可以帮助我们得到这些属性。    
   
  类   PoorChinese   的源代码:    
   
  public   class   PoorChinese   {    
   
        public   static   void   main(String[]   args)   {    
   
                System.getProperties().list(System.out);    
   
        }    
   
  }    
   
  执行   java   PoorChinese   后,我们会得到:    
   
  系统变量   file.encoding   的值为   GBK   ,user.language   的值为   zh   ,   user.region   的值为   CN   ,这些系统变量的值决定了系统默认的编码方式是   GBK   。    
   
  在上述系统中,下面的代码将   GB2312   文件转换成   Big5   文件,它们能够帮助我们理解   Java   中汉字编码的转化:


import java.io.*;

import java.util.*;



public class gb2big5 {



static int iCharNum=0;



public static void main(String[] args) {

System.out.println("Input GB2312 file, output Big5 file.");

if (args.length!=2) {

System.err.println("Usage: jview gb2big5 gbfile big5file");

System.exit(1);

}

String inputString = readInput(args[0]);

writeOutput(inputString,args[1]);

System.out.println("Number of Characters in file: "+iCharNum+".");

}



static void writeOutput(String str, String strOutFile) {

try {

FileOutputStream fos = new FileOutputStream(strOutFile);

Writer out = new OutputStreamWriter(fos, "Big5");

out.write(str);

out.close();

}

catch (IOException e) {

e.printStackTrace();

e.printStackTrace();

}

}



static String readInput(String strInFile) {

StringBuffer buffer = new StringBuffer();

try {

FileInputStream fis = new FileInputStream(strInFile);

InputStreamReader isr = new InputStreamReader(fis, "GB2312");

Reader in = new BufferedReader(isr);

int ch;

while ((ch = in.read()) > -1) {

iCharNum += 1;

buffer.append((char)ch);

}

in.close();

return buffer.toString();

}

catch (IOException e) {

e.printStackTrace();

return null;

}

}

}

 

 
   
       
   
   
  编码转化的过程如下:    
   
                ByteToCharGB2312                   CharToByteBig5    
   
  GB2312------------------>Unicode------------->Big5    
   
  执行   java   gb2big5   gb.txt   big5.txt   ,如果   gb.txt   的内容是“今天星期三”,则得到的文件   big5.txt   中的字符能够正确显示;而如果   gb.txt   的内容是“情人节快乐”,则得到的文件   big5.txt   中对应于“节”和“乐”的字符都是符号“?”(0x3F),可见   sun.io.ByteToCharGB2312   和   sun.io.CharToByteBig5   这两个基本类并没有编好。    
   
  正如上例一样,   Java   的基本类也可能存在问题。由于国际化的工作并不是在国内完成的,所以在这些基本类发布之前,没有经过严格的测试,所以对中文字符的支持并不像   Java   Soft   所声称的那样完美。前不久,我的一位技术上的朋友发信给我说,他终于找到了   Java   Servlet   中文问题的根源。两周以来,他一直为   Java   Servlet   的中文问题所困扰,因为每面对一个含有中文字符的字符串都必须进行强制转换才能够得到正确的结果(这好象是大家公认的唯一的解决办法)。后来,他确实不想 如此继续安分下去了,因为这样的事情确实不应该是高级程序员所要做的工作,他就找出   Servlet   解码的源代码进行分析,因为他怀疑问题就出在解码这部分。经过四个小时的奋斗,他终于找到了问题的根源所在。原来他的怀疑是正确的,   Servlet   的解码部分完全没有考虑双字节,直接把   %XX   当作一个字符。(原来   Java   Soft   也会犯这幺低级的错误!)    
   
  如果你对这个问题有兴趣或者遇到了同样的烦恼的话,你可以按照他的步骤对   Servlet.jar   进行修改:    
   
  找到源代码   HttpUtils   中的   static   private   String   parseName   ,在返回前将   sb(StringBuffer)   复制成   byte   bs[]   ,然后   return   new   String(bs,”GB2312”)。作上述修改后就需要自己解码了:    
   
  HashTable   form=HttpUtils   .parseQueryString(request.getQueryString())或者    
   
  form=HttpUtils.parsePostData(……)    
   
  千万别忘了编译后放到   Servlet.jar   里面。    
   
  五、   关于   Java   中文问题的总结    
   
  Java   编程语言成长于网络世界,这就要求   Java   对多国字符有很好的支持。   Java   编程语言适应了计算的网络化的需求,为它能够在网络世界迅速成长奠定了坚实的基础。   Java   的缔造者   (Java   Soft)   已经考虑到   Java   编程语言对多国字符的支持,只是现在的解决方案有很多缺陷在里面,需要我们付诸一些补偿性的措施。而世界标准化组织也在努力把人类所有的文字统一在一种编 码之中,其中一种方案是   ISO10646   ,它用四个字节来表示一个字符。当然,在这种方案未被采用之前,还是希望   Java   Soft   能够严格地测试它的产品,为用户带来更多的方便。    
   
  附一个用于从数据库和网络中取出中文乱码的处理函数,入参是有问题的字符串,出参是问题已经解决了的字符串。  

public static String parseChinese(String in)

{
String s = null;
byte temp[];
if (in == null)
{
System.out.println("Warn:Chinese null founded!");
return new String("");
}
try
{
temp = in.getBytes("iso-8859-1");
s = new String(temp);
}

catch (UnsupportedEncodingException e)
{
System.out.println(e.toString());
}
return s;
}
 

 
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值