第三章 深入分析Java Web中的中文编码问题

2018-04-09  本文已影响22人  01_小小鱼_01

一、常见的编码格式

1.1 为啥要进行编码
1.2 编码

如果是 1 个字节,最高位(第 8 位)为 0,则表示这是一个 ASCII 字符(00 ~ 7F)
如果是 1 个字节,以 11 开头,则连续的 1 的个数暗示这个字符的字节数
如果是 1 个字节,以 10 开头,表示它不是首字节,则需要向前查找才能得到当前字符的首字节

二、Java 中需要编码的场景

2.1 I/O 操作中存在的编码

我们知道涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍。下图是 Java 中处理 I/O 问题的接口:

Figure xxx. Requires a heading

Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现它由 StreamDecoder 去实现,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码。

写的情况也是类似,字符的父类是 Writer,字节的父类是 OutputStream,通过 OutputStreamWriter 转换字符到字节。如下图所示:

Figure xxx. Requires a heading

同样 StreamEncoder 类负责将字符编码成字节,编码格式和默认编码规则与解码是一致的。

如下面一段代码,实现了文件的读写功能:

String file = "c:/stream.txt"; 
String charset = "UTF-8"; 
// 写字符换转成字节流
FileOutputStream outputStream = new FileOutputStream(file); 
OutputStreamWriter writer = new OutputStreamWriter( 
outputStream, charset); 
try { 
   writer.write("这是要保存的中文字符"); 
} finally { 
   writer.close(); 
} 
// 读取字节转换成字符
FileInputStream inputStream = new FileInputStream(file); 
InputStreamReader reader = new InputStreamReader( 
inputStream, charset); 
StringBuffer buffer = new StringBuffer(); 
char[] buf = new char[64]; 
int count = 0; 
try { 
   while ((count = reader.read(buf)) != -1) { 
       buffer.append(buffer, 0, count); 
   } 
} finally { 
   reader.close(); 
}

在我们的应用程序中涉及到 I/O 操作时只要注意指定统一的编解码 Charset 字符集,一般不会出现乱码问题,有些应用程序如果不注意指定字符编码,中文环境中取操作系统默认编码,如果编解码都在中文环境中,通常也没问题,但是还是强烈的不建议使用操作系统的默认编码,因为这样,你的应用程序的编码格式就和运行环境绑定起来了,在跨环境下很可能出现乱码问题。

2.2 内存中操作中的编码

在 Java 开发中除了 I/O 涉及到编码外,最常用的应该就是在内存中进行字符到字节的数据类型的转换,Java 中用 String 表示字符串,所以 String 类就提供转换到字节的方法,也支持将字节转换为字符串的构造函数。如下代码示例:

String s = "这是一段中文字符串"; 
byte[] b = s.getBytes("UTF-8"); 
String n = new String(b,"UTF-8");

Charset 提供 encode 与 decode 分别对应 char[] 到 byte[] 的编码和 byte[] 到 char[] 的解码。如下代码所示:

Charset charset = Charset.forName("UTF-8"); 
ByteBuffer byteBuffer = charset.encode(string); 
CharBuffer charBuffer = charset.decode(byteBuffer);

参考文章

1. 深入分析 Java Web 中的中文编码问题

上一篇下一篇

猜你喜欢

热点阅读