萍聚社区-德国热线-德国实用信息网

 找回密码
 注册

微信登录

微信扫一扫,快速登录

查看: 1713|回复: 8

1-1-16-3-1 Java繁体中文处理完全攻略(一)

[复制链接]
发表于 2003-5-11 23:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册 微信登录

x
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(一)
发信站: BBS 水木清华站 (Sat Jul 13 19:54:01 2002)

许多人用 Java 处理到中文资料时,常会出现乱码。关于 Java 和中文兼容性的问题,实
在让许多程序员为此伤透脑筋,相关的问题每隔几天就会出现在网络上。为了舒缓您紧蹙
的眉头,我特别写了这系列文章,解说 Java 牵涉到文字时的内部处理方式,供读者参考
。读完本系列文章之后,不求甚解者可以治标,充分理解者可以治本。本文贵在原理解说

快速解决之道

如果你目前正遭遇到 Java 和中文不兼容的问题,请你注意下面这几点,说不定问题能马
上迎刃而解:

1.          检查操作系统设定:先检查你的操作系统,确定国籍语言资料是「Traditio
nal Chinese(Taiwan)」。国籍语言资料的设定会影响 Java 编译器与JRE的判断。我之
前就是因为国籍资料设定不正确,出了一堆 Java 和中文不兼容的怪事。

2.          更新 Java 环境版本:改用最新版的 JDK,新版本的 JDK 说不定已经解决你
原有的问题。请注意:某些 Java IDE 所用的编译器和 JRE 是不兼容于中文的(我遇过这
样的情形),你最好能把 Java IDE 的 JDK 指到新版的 JDK。另外,如果数据库取回的资
料是乱码,换别套或者更新 JDBC 驱动程序试试看。

如果还是无法解决,请详细阅读下面各小节的内容,仔细推敲你的错误所在。

待续......

--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:58 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(二)
发信站: BBS 水木清华站 (Sat Jul 13 19:55:10 2002)

Unicode、UTF-16、UTF-8

Java 内部处理字符使用的字序方式是 Unicode,这是一种通行全球的编码方式。Unicode
因为必须将中、韩、日、英、法、阿拉伯……等许多国家所使用的文字都纳入,目前已经
包含了六万多个字符,所以 Unicode 使用了 16 个位来为字符编码。因为 Unicode 使用
了 16 位编码,所以每个字符都用 16 位来储存或传输是很自然的事,这种储存或传输的
格式称为 UTF-16(是不是很像战斗机的名字)。如果你使用到的字符都是西方字符,那么
你一定不会想用 UTF-16 的格式,因为体积比 8 位的 Latin-1(一种扩充 ASCII 的编码
)多了一倍。所以 Unicode 另有一种储存或传输的格式,叫做 UTF-8。UTF-8 的格式在编
码英文时,只需要 8 位,但是中文则是 24 位,所以中文字出现比例高的地方还是使用
UTF-16 比较节省空间。Java 的 Class File(也就是 bytecode)中有一字段叫做常数区
(Constant Pool),一律使用 UTF-8 为字符编码。

关于 Unicode 的编码,请查阅「The Unicode Standard, Version 3.0」一书(Addison-
Wesley 出版);关于 UTF-8 编码,请查阅「Java I/O」一书的 399 页(O'Reilly 出版
)。关于 Java Class File 的格式与 Constant Pool,请查阅「Java Virtual Machine」
一书(O'Reilly出版)。


--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:58 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(三)
发信站: BBS 水木清华站 (Sat Jul 13 19:56:02 2002)

Unicode 与繁体中文编码的互转

虽然 Java 内部完整地使用 Unicode,但是你所使用的操作系统可不见得。以繁体中文版
的 Windows 98 来说,预设的编码方式是 MS950,这是一种兼容于 Big 5的编码方式。字
符串数据从 Windows 一送进 JRE,JRE 的转码系统马上先把字符串编码由 MS950 转成 U
nicode,才能进行处理。字符串资料由 JRE 一送出给 Windows,JRE 的转码系统马上先将
其由 Unicode 转成 MS950,操作系统才能处理。

想知道你的 JDK 或 JRE 会用什么样的编码方式来和操作系统沟通,请执行下面的 Java
程序:

public class ShowNativeEncoding {

       public static void main(String[] args) {

       String enc = System.getProperty("file.encoding");

       System.out.println(enc);

}

}

如果执行结果不是下面的字符串之一,那么你的操作系统国籍语言设定可能就有问题了:


· Big5:这是繁体中文 de facto 标准。

· CNS11643:台湾的官方标准繁体中文编码。

· Cp937:繁体中文加上 6204 个使用者自定的字符

· Cp948:繁体中文版 IBM OS/2 用的编码方式。

· Cp964:繁体中文版 IBM AIX 用的编码方式。

· EUC_TW:台湾的加强版 Unicode。

· ISO2022CN:编码中文的一套标准。


· MS950 或 Cp950:ASCII + Big5,用于台湾和香港的繁体中文 MS Windows操作系统。


· Unicode:有次序记号的 Unicode。次序记号占用两个 byte,如果其值是0xFEFF,表示
使用 big-endian(由大到小)的次序为 Unicode 编码;如果其值是 0xFFFF,表示使用
little-endian(由小到大)的次序为 Unicode 编码。

· UnicodeBig:使用 big-endian(由大到小)的次序为 Unicode 编码。

· UnicodeLittle:使用 little-endian(由小到大)的次序为 Unicode 编码。

· UTF8:使用 UTF-8 为 Unicode 编码。

关于 Big 5 编码,请查阅「CJKV Information Processing」一书的附录 H(O'Reilly出
版)。



--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:58 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(四)
发信站: BBS 水木清华站 (Sat Jul 13 19:57:03 2002)

编译时的注意事项

编译的时候,如果你不说明原始文件编码方式的话, javac 编译器在读进此原始程序文件
,开始编译之前,会先去询问操作系统档案预设的编码方式为何。以繁体中文 Windows 9
8 来说,javac 会先询问 Windows 98,得知档案是用 MS950 的方式编码。然后就可以将
档案由 MS950 转成 Unicode 编码方式,开始进行编译。

通常在编译阶段,会造成的错误有下列几种可能:

1.           如果操作系统的国籍资料设定错误,会造成 javac 编译器取得的编码信息
是错的。

2.           较差劲的编译器可能没有主动询问操作系统的编码方式,而是采用编译器预
设的编码方式。

3.           如果原始程序不是用编译当时操作系统预设的编码方式存盘的,也会造成错
误。比方说,原始程序文件是台湾程序员写的,在繁体中文版的 Windows上以 MS950 编码
存盘,再经由网络传送到泰国,在泰文版的 Windows 上编译(泰文版 Windows 预设的档
案编码方式是 MS874)。

这种因为原始程序文件编码方式和编译器无法匹配所造成的问题,轻则编译成功但执行时
文字出现乱码或出现 Error/Exception,重则无法成功编译。这时候,你需要主动透过「
-encoding」选项来指定原始程序的编码方式,编译器会以你指定的编码为主,不会再去询
问操作系统。下面的例子,我们告诉编译器「TaiwanClass.java」是以繁体中文版 Windo
ws 的「MS950」编码的:

       javac –encoding MS950 TaiwanClass.java

如果你手上只有某 class 文件,没有原始程序文件,而且你确定其 constant pool 的UT
F-8 字段编码错误,你有两种方式可以用来修正编码:

1.  先反编译,取得原始程序,再修改,编译。

2.  或者直接利用 bytecode 编辑软件,直接修改 class 文件。



--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:59 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(五)
发信站: BBS 水木清华站 (Sat Jul 13 20:06:08 2002)

I/O 转码
Java 现行的 IO 一律使用 Stream 的方式,相关的类别都放在 java.io 中。输出 binar
y 的资料使用 OutputStream 的子类别,输入 binary 的资料使用 InputStream 的子类别
,输出文字的资料使用 Writer 的子类别,输入文字的资料使用 Reader 的子类别。

你可能会觉得很奇怪:「有必要用不同的方式来处理文字和 binary 吗?文字资料不也是
binary 的一种?」没错,其实他们非常类似,最大的差异在于,InputStream/OutputSt
ream 会原封不动地传送资料,但是 Reader/Writer 会将资料当作文字对待,所以 Reade
r/Writer 在「必要时」会把(文字)资料转码。什么时候才是所谓的「必要时」呢?

Java 的 Stream(包括 Reader 和 Writer)是可以互相串接的。当 Reader 的资料来源是
另一个 Reader 时,不转码,当 Reader 的资料来源是一个 InputStream 时,就会转码。
当 Writer 的资料去处是另一个 Writer 时,不转码,当 Writer 的资料去处是一个 Out
putStream 时,就会转码。

由什么码转成什么码?这是可以指定的。因为转码只发生在 Reader/InputStream 的交界
处与 Writer/OutputStream 的交界处,所以正是由 InputStreamReader 和 OutputStrea
mWriter 此二类别负责,下面两个 constructor 的第二个参数,正是用来指定转码的方式

public InputStreamReader(InputStream in, String enc)
         throws UnsupportedEncodingException;
public OutputStreamWriter(OutputStream out, String enc)
         throws UnsupportedEncodingException;

InputStreamReader 负责将 enc 的编码方式转成 Unicode(因为资料是从「外部」送过来
给「内部」的),OutputStreamWriter 负责将 Unicode 的编码方式转成 enc(因为资料
要从「内部」送给「外部」)。JRE 内部当然都一定是用 Unicode 编码,而外部的编码就
不一定,要看当时的环境为何。你可以透过 getEncoding() 的 method,来得知 InputSt
reamReader 与 OutputStreamWriter 的编码方式。

请注意:即使你没用到 InputStreamReader 与 OutputStreamWriter,只有用到其它的 R
eader 和 Writer,但是这些 Reader 和 Writer 内部也很有可能(但非绝对)是直接或间
接通到 InputStreamReader 与 OutputStreamWriter。比方说:FileReader 内部其实是透
过一个 InputStreamReader 的中介来将资料从 FileInputStream 取过来的,此时 Input
StreamReader 的转码方式是采用 OS 的文字编码(以繁体中文的 Windows 为例,就是「
MS950」)转成 Unicode。

如果你清楚地知道你要读写的档案(或资料来源 / 去处)是采用某种编码方式,你也可以
主动指定编码方式。但是,请记得抓取可能导致的 UnsupportedEncodingException,并务
必处理之,不可对此例外置之不理,因为该 JRE 有可能没有附上此种编码表(也有可能你
的编码名称给错)。



--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:59 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(六)
发信站: BBS 水木清华站 (Sat Jul 13 20:06:45 2002)

档案 I/O 转码
如果你是在泰文版的 Windows 上,想读取用 MS950 编码的繁体中文文字文件,你就必须
主动指定编码,不可以直接用 FileReader,否则无法成功读取。方法如下:

FileInputStream fis = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(fis, "MS950");

然后,透过 Reader 读出来的就会是正确的中文。



--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:59 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java繁体中文处理完全攻略(七)
发信站: BBS 水木清华站 (Sat Jul 13 20:07:33 2002)



[Java FAQ]
Java 繁体中文处理完全攻略(二)
I/O 转码
Java 现行的 IO 一律使用 Stream 的方式,相关的类别都放在 java.io 中。输出 binar
y 的资料使用 OutputStream 的子类别,输入 binary 的资料使用 InputStream 的子类别
,输出文字的资料使用 Writer 的子类别,输入文字的资料使用 Reader 的子类别。

你可能会觉得很奇怪:「有必要用不同的方式来处理文字和 binary 吗?文字资料不也是
binary 的一种?」没错,其实他们非常类似,最大的差异在于,InputStream/OutputSt
ream 会原封不动地传送资料,但是 Reader/Writer 会将资料当作文字对待,所以 Reade
r/Writer 在「必要时」会把(文字)资料转码。什么时候才是所谓的「必要时」呢?

Java 的 Stream(包括 Reader 和 Writer)是可以互相串接的。当 Reader 的资料来源是
另一个 Reader 时,不转码,当 Reader 的资料来源是一个 InputStream 时,就会转码。
当 Writer 的资料去处是另一个 Writer 时,不转码,当 Writer 的资料去处是一个 Out
putStream 时,就会转码。

由什么码转成什么码?这是可以指定的。因为转码只发生在 Reader/InputStream 的交界
处与 Writer/OutputStream 的交界处,所以正是由 InputStreamReader 和 OutputStrea
mWriter 此二类别负责,下面两个 constructor 的第二个参数,正是用来指定转码的方式


public InputStreamReader(InputStream in, String enc)
         throws UnsupportedEncodingException;
public OutputStreamWriter(OutputStream out, String enc)
         throws UnsupportedEncodingException;

InputStreamReader 负责将 enc 的编码方式转成 Unicode(因为资料是从「外部」送过来
给「内部」的),OutputStreamWriter 负责将 Unicode 的编码方式转成 enc(因为资料
要从「内部」送给「外部」)。JRE 内部当然都一定是用 Unicode 编码,而外部的编码就
不一定,要看当时的环境为何。你可以透过 getEncoding() 的 method,来得知 InputSt
reamReader 与 OutputStreamWriter 的编码方式。

请注意:即使你没用到 InputStreamReader 与 OutputStreamWriter,只有用到其它的 R
eader 和 Writer,但是这些 Reader 和 Writer 内部也很有可能(但非绝对)是直接或间
接通到 InputStreamReader 与 OutputStreamWriter。比方说:FileReader 内部其实是透
过一个 InputStreamReader 的中介来将资料从 FileInputStream 取过来的,此时 Input
StreamReader 的转码方式是采用 OS 的文字编码(以繁体中文的 Windows 为例,就是「

如果你清楚地知道你要读写的档案(或资料来源 / 去处)是采用某种编码方式,你也可以
主动指定编码方式。但是,请记得抓取可能导致的 UnsupportedEncodingException,并务
必处理之,不可对此例外置之不理,因为该 JRE 有可能没有附上此种编码表(也有可能你
的编码名称给错)。

档案 I/O 转码
如果你是在泰文版的 Windows 上,想读取用 MS950 编码的繁体中文文字文件,你就必须
主动指定编码,不可以直接用 FileReader,否则无法成功读取。方法如下:

FileInputStream fis = new FileInputStream(fileName);

然后,透过 Reader 读出来的就会是正确的中文。

网络 I/O 转码
如果你的网络程序采用 TCP,那么你可以透过 Socket 类别所提供的 getInputStream()
和 getOutputStream() 来得到 InputStream 和 OutputStream 对象。如果你是在泰文版
的 Windows 上,想读取用 MS950 编码的繁体中文文字 TCP 网络串流,你可以用类似上面
的技巧来转码。方法如下:

InputStream is = mySocket.getInputStream();
InputStreamReader reader = new InputStreamReader(is, "MS950");

如果你的网络程序采用 UDP,你必须把中文字符串转成(或转自)byte 数组。请看下一节
「 字符串和 byte 数组的转码 」。

如果你的网络程序采用 RMI,那你完全不用为这部分的转码操心,字符串直接用 Unicode
在网络上传递给另一个 JRE,不需要转码。


--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.205.91.252]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-11 23:59 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java 繁体中文处理完全攻略(八)
发信站: BBS 水木清华站 (Sat Jul 13 20:08:16 2002)

保持刑案现场

如果你不知道你的 I/O 资料来源或去处是用何种编码方式,那么你最好不要用 Reader 和
Writer,而应该直接用 InputStream 和 OutputStream,因为与其被 Reader 和 Writer
胡乱编码之后造成信息遗失或错乱,不如保持资料的完整不变,留待以后进一步解读。
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
 楼主| 发表于 2003-5-12 00:00 | 显示全部楼层
发信人: kulersh (不爱那么多,只爱一点点), 信区: Java
标  题: Java 繁体中文处理完全攻略(九)
发信站: BBS 水木清华站 (Sat Jul 13 20:09:08 2002)

字符串和 byte 数组的转码
java.lang.String 类别是 Java 字符串对象的类别,Java 字符串对象既然是活在 JRE 内
部,当然就一定是用 Unicode 编码。如果你需要将 String 对象和 byte 数组互转,你可
以使用:

String(byte[] bytes, int offset, int length, String enc);

          或

String(byte[] bytes, String enc);

来将用 enc 编码的 byte 数组,转成 Unicode 的 String 对象。你也可以使用 String
对象所提供的:

byte[] getBytes(String enc)

来将 String 对象转成 byte 数组。

另外,你也可以透过 ByteArrayInputStream 或 ByteArrayOutputStream 串接到 InputS
treamReader 或 OutputStreamWriter,来达到转码的目的。


--
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
您需要登录后才可以回帖 登录 | 注册 微信登录

本版积分规则

手机版|Archiver|AGB|Impressum|Datenschutzerklärung|萍聚社区-德国热线-德国实用信息网 |网站地图

GMT+2, 2024-6-15 01:05 , Processed in 2.571742 second(s), 20 queries , MemCached On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表