深入分析 Java Web 中的中文编码问题(一)

2017/10/14

几种常见的编码格式

计算机如何表示人类能够理解的符号的?

由于人类语言过多,无法用计算机中一个基本的存储单元 字节 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机理解我们的语言。可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须得经过一次翻译,翻译成英语。这个翻译的过程就是编码。只要不是说英语的国家,要使用计算机就必须经过编码。

编码的原因

  • 计算机中存储信息的最小单元是 1 个字节,即 8 个 bit,所以能表示的字符范围 0 ~ 255 个。
  • 人类要表示的符号太多,无法用 1 个字节来完全表示。

解决这个矛盾必须要有一个新的数据结构 char ,而从 charbyte 必须编码。

如何翻译

计算机提供了多种翻译方式,如:ASCIIISO-8859-1GB2312GBKUTF-8UTF-16等。他们都可以看作字典,规定了转化规则。

编码格式

  • ASCII 共 128 个,用 1 个字节的低 7 位表示。
  • ISO-8859-1 在 ASCII 基础上扩展,涵盖了大多数西欧语言字符。但仍然是单字节编码,共能表示 256 个字符。
  • GB2312 双字节编码。
  • GBK 在 GB2312 上进行扩展,并加入更多的汉字。GB2312 编码的汉字可以用 GBK 来解码。
  • UTF-16 定义了 Unicode 字符在计算机中的存取方法,用两个字节来表示 Unicode 的转化格式,采用定长表示,无论什么字符都可以用两个字节表示。两个字节 16 个 bit 所以叫 UTF - 16。JAVA 以 UTF-16 做为内存的字符存储格式。
  • UTF-8 UTF-8 采用变长,不同的字符可以由 1 ~ 6 个字节表示。比 UTF-16 占用小。

在 Java 中需要编码的场景

1、在 I/O 中存在的编码

涉及编码的地方一般都在从字符到字节或从字节到字符的转换上,而需要这种转换的场景主要是 I/O。 Reader 类是在 Java 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁。负责处理读取字节到字符的转换,面对具体字节到字符的解码实现它又委托 StreamDecoder 去做,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。如果不指定默认使用本地环境中的默认字符集。 涉及 I/O 操作时,只要注意指定统一的编解码 Charset 字符集,一般不会出现乱码问题。不建议使用操作系统默认编码,跨环境可能出现乱码。

2、在内存操作中的编码

除 I/O 涉及编码外,最常用的应该就是在内存中进行从字符到字节的转换,String 表示字符串,提供了到字节的方法,也支持字节到字符的构造函数。

参考

  • 《深入分析Java Web技术内幕》(修订版) 许令波 著
发表评论

Post Directory