?????????????????? 第一篇: 深入浅出Java中的中文乱码
一、为什么会有中文乱码:
其实很简单,一句话就能说明问题: 字符在保存时的编码格式如果和要显示(解码)时的编码格式不一样的话,就会出现乱码问题。
?
二、需要了解的事实:
?????? 1. Java中的任何String都是以UNICODE格式存在的。class="Apple-converted-space">
????? 很多人因为在GBK环境中使用String,会误以为String是GBK格式,实际上Java的String类中并没有存储CharSet信息的字段, 所有String中的字符只会以UNICODE的2字节形式存在。
?
?????? 2. String在构造时会逐一把字符按指定编码(默认值为系统编码GBK),转换为UNICODE字符,存入一个Char数组中,二这个Char数组中的元素都是无符号的16为字符。
如:对于java代码:new String(bytes, "gbk"):这并不是说,生成一个GBK编码的字符串,而JDK讲会按GBK的编码逐一的讲字节数组bytes中的字符转化为UNICODE的编码。?
?????? 假设,bytes本是按GBK编码的,构造方法在发现一个最高位为0的byte就作为ascii字符处理,如果发现最高位为1,那么就和后面的一个byte合成中文字符,再转换编码。?
?????? 可以看出,在这个过程,编码选择错误就会导致程序按错误方法辨认bytes,乱码就出现了。?
?????? 其实这种情况下产生的乱码,很多时候还可以通过.getBytes()方法修复。
??????? 如:"中".getBytes("iso-8859-1");因为iso-8859-1是西欧编码,没有中文,所以"中"字被替换成63,显示'?',无法判断以前是什么值,从而显示乱码。所以如下String将被产生乱码:?
new String("中文".getBytes("iso-8859-1"), "iso-8859-1");?
??????? 但如果目标编码方式支持中文,就不会损坏String:new String("中文".getBytes("utf-8"),"utf-8");?
??????? 3. Java在显示字符时,还需要进行一次转换,把UNICODE字符转换成用于显示的字符编码形式。?
?????? 其实很多时候,这个过程是自动的,会按系统的默认编码(一般是GBK)转换String。所以很明显如果指定转换的编码和我们指定的页面编码不一样,就会出现乱码。
这也说明虽然在Java的程序中只有一种编码(Unicode编码), 但是输出却可以有不同的编码。?
?
???????? 4. 有时候,我们需要用 iso-8859-1格式分解String的中文,以便在不支持中文的系统中存储:?
new String("中文".getBytes("GBK"),"iso-8859-1");先通过GBK等支持中文的编码方式分解为byte数组,再作为iso-8859-1字符以组成字符串,这样就可避免了被替换为Char(63)。
?
三、需要了解的几个概念:
??????? 1. 要想解决java中文乱码问题,首先就有必要了解一下什么是字符,字符集,编码的概念。
??????? 1) 字符:是文字与符号的总称,包括文字、图形符号、数学符号等。
??????? 2)字符集:就是一组抽象字符的集合。
?????????? 字符集常常和一种具体的语言文字对应起来,该文字中的所有字符或者大部分常用字符就构成了该文字的字符集,比如英文字符集。繁体汉字字符集、日文汉字字符集等等。
? ? ??? 3)编码: 计算机要处理各种字符,就需要将字符和二进制编码对应起来,这种对应关系就是字符编码。
?????? 制定编码首先要确定字符集,并将字符集内的字符排序,然后和二进制数字对应起来。根据字符集内字符的多少,会确定用几个字节来编码。每种编码都限定了一个明确的字符集合,叫做被编码过的字符集(Coded Character Set),这是字符集的另外一个含义。
????????? 2. 常用的编码格式:
1) ASCII编码是目前计算机中用得最广泛的字符集及其编码。
2)ISO8859-1表示的是西欧语言的编码。由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,即时ISO8859-1表示的字符有限,但仍旧使用ISO-8859-1。 而且在很多协议上,默认使用该编码。
3)Unicode(统一码、万国码、单一码) 是一种在计算机上使用的字符编码。通常我们所遇到过多UTF-8正是Unicode编码的实现方式。
4)GB2312字集是简体字集;BIG5字集是台湾繁体字集;GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号。
5)GB18030是国家制定的一个强制性大字集标准,它的推出使汉字集有了一个统一的标准。
6)Linux系统默认使用的是ISO-8859-1编码,Win32系统默认使用的是GB2312编码。
?
??????? 3. 开发中怎样避免乱码问题
1) 开发环境编码要一致。如页面编码,数据库编码等。
????? Java在运行期一律以Unicode来存储字符,这样有利的支持了多语言环境。我们在开发过程中经常会用到文件读取。Java读文件的时候会用到系统默认的编码来解码文件。所以在用FileInputStream类读取文件可以指定编码读取。当然也可以在字节流和字符流相互转换时使用编码,如在InputStreamRedaer和OutputStreamWriter类中指定编码。
2) JSP页面乱码通常只要在页面开始地方用下面代码指定字符集编码即可。如果还不行,可以用如下的代码来转换 str=new String(str.getBytes("ISO-8859-1"),"页面编码方式");?
?
3)使用正确的方式来解码:
JAVA在网络传输中使用的编码是"ISO-8859-1",故在输出时需要进行转化,如:?
String str=new String(str.getBytes("开发环境编码"), "ISO-8859-1");
经过网络编码后的中文,要正确显示在页面上必须要用类似于下面的方式来解码:
Stirng str=new String(str.getBytes("ISO-8859-1"),"开发环境编码");
?
下一篇讲详细讲解另一个问题:Spring中@ResponseBody中的中文乱码问题。
http://josh-persistence.iteye.com/blog/2085015
?
?