不怕明说,其实计算机只理解数字。但下面这一点可能就没那么明显 ― 因为计算机只理解数字,所以它们需要用某种形式把数字值映射为相应的字符,这样才能显示文本。就是这些映射(或 字符集)才使得计算机可以理解文本。例如,就为了这种映射,早期的台式机使用了 ASCII。当一台使用 ASCII 的计算机存储数字 72、101、108 和 112 时,它便知道要显示“Help”这个单词,因为在 ASCII 中,数字 72 是 H 的值、101 是 e 的值、108 是 l 的值、112 是 p 的值。但如果这台计算机是早期的 IBM 大型机(它使用 EBCDIC 而不是 ASCII),“Help”这个单词将用数字 200、133、147 和 151 代表。
在向 Java 语言迁移时,
java.nio.charset 包中有三个类帮助进行这种映射:
Charset 、
CharsetEncoder 和
CharsetDecoder 。这些类相互配合,这样您就可以先采用一种映射,然后将其转换为另一种映射。在从另一种映射转换为 Java 映射(Unicode)时,您可以使用解码器(decoder)。然后,如果您需要从 Java 映射(Unicode)再转换为另一种映射(或转换回原来那种映射)时,您可以使用编码器(encoder)。您无法用
java.nio.charset 包在两种非 Unicode 格式之间直接转换,但您可以通过一种中间的 Unicode 格式在两种非 Unicode 格式间进行转换。
在得到一个解码器或编码器之前,您需要获得用于特定映射的
Charset 。例如,US-ASCII 是用于 7 位 ASCII 字符集的映射的名称。您只需象下面这样把该名称传递到
Charset 的
forName() 方法中即可:
Charset charset =
Charset.forName("US-ASCII");
|
一旦有了
Charset ,只需按如下所示请求
CharsetDecoder 和
CharsetEncoder :
CharsetDecoder decoder = charset.newDecoder(); CharsetEncoder encoder = charset.newEncoder(); |
有了解码器和编码器后,您就可以在不同的字符集之间进行转换了,如下所示:
ByteBuffer bytes = ...; CharBuffer chars = decoder.decode(bytes); bytes = encoder.encode(chars); |
当然,如果不确定哪些字符集可用,您需要用下面的语句来询问:
SortedMap map = Charset.availableCharsets(); |
然后您将使用特定的解码器把外部字节转换为内部字符。然后,如果需要把数据发送到 Java 代码外,您将使用编码器把内部字符转换为外部字节。至于哪些特定的字符集可用,您的运行时将确定整个字符集。但每个 Java 编程实现都必须支持下列编码:
- US-ASCII:7 位 ASCII
- ISO-8859-1:ISO 拉丁字母
- UTF-8:8 位 UCS 转换格式
- UTF-16BE:16 位 UCS 转换格式,大尾数法字节顺序
- UTF-16LE:16 位 UCS 转换格式,小尾数法字节顺序
- UTF-16:16 位 UCS 转换格式,用标记(marker)识别的字节顺序
然后,不同的平台可能支持特定于该平台的额外字符集(例如,在 Windows 平台上,您会发现它支持 Windows-1252 字符集)。如果您需要支持其他的字符集,您可以创建自己的字符集。请参阅
java.nio.charset.spi 包中的 CharsetProvider API。
清单 1 通过转换单词“Help”的 ASCII 字节数组值(72、101、108 和 112)演示了 Java 字符集转换功能。遗憾的是,缺省情况下没有 EBCDIC 编码器,所以我们将把值转换为 UTF-16LE 字符数组(这只是为每个字符的第二个字节添加一个“0”字节)。
清单 1. 字符集转换示例
import java.nio.*;
import java.nio.charset.*;
import java.util.Arrays;
public class Convert {
public static void main(String args[]) {
System.out.println(Charset.availableCharsets());
Charset asciiCharset = Charset.forName("US-ASCII");
CharsetDecoder decoder = asciiCharset.newDecoder();
byte help[] = {72, 101, 108, 112};
ByteBuffer asciiBytes = ByteBuffer.wrap(help);
CharBuffer helpChars = null;
try {
helpChars = decoder.decode(asciiBytes);
} catch (CharacterCodingException e) {
System.err.println("Error decoding");
System.exit(-1);
}
System.out.println(helpChars);
Charset utfCharset = Charset.forName("UTF-16LE");
CharsetEncoder encoder = utfCharset.newEncoder();
ByteBuffer utfBytes = null;
try {
utfBytes = encoder.encode(helpChars);
} catch (CharacterCodingException e) {
System.err.println("Error encoding");
System.exit(-1);
}
byte newHelp[] = utfBytes.array();
for (int i=0, n=newHelp.length; i<n; i++) {
System.out.println(i + " :" + newHelp[i]);
}
}
}
|
注意:除手工执行编码和解码外,您还可以向
java.ioInputStreamReader 和
java.ioOutputStreamWriter 构造函数提供一个字符集,让它们为您执行转换工作。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 单击文章顶部或底部的
讨论参加关于本文的
讨论论坛。
- 下载本文中使用的
字符集转换示例的源代码。
- 阅读
java.nio.charset包的 API 文档。
- 阅读
java.lang包的 1.3 API 文档。
- 学习“
RFC2278”中字符集的正式定义。
- 看一下
Internet Assigned Numbers Authority (IANA) 处的字符集注册情况。
- 在
ASCII 表中查找字符代码。
- 通过
Unicode 常见问题解答学习 Unicode。
- 阅读 Mark Davis 的文章“
Java cookbook: Creating global applications”(
developerWorks,1998 年 1 月),学习有关国际化的知识。
- 刚开始使用 1.4?请务必查看 John Zukowski 的
Merlin 的魔力
技巧全集。
- 在
developerWorks
Java 技术专区查找更多的 Java 语言参考资料。
John Zukowski 担任 JZ Ventures,Inc.的 Java 战略咨询工作,他还充当很多 jGuru社区发起的 Java 常见问题解答的常驻导师。他最新的两本书是 Apress 出版的 Learn Java with JBuilder 6 和 Sybex 出版的 Mastering Java 2: J2SE 1.4 。请通过 jaz@zukowski.net与 John 联系。