读书人

总结java中文乱码有关问题

发布时间: 2012-11-13 10:00:50 作者: rapoo

总结java中文乱码问题!

??? 出现乱码问题主要是因为字符集编码的问题。而java的底层是Unicode编码的,用Unicode处理字符,单在文件和流中是使用字节流的。因此java需要对字节流和字符进行转换。转换中,编码和解码使用的字符集不一致,就会导致中文乱码问题。

??? 中文系统的默认编码方式是GBK,java会根据操作系统的默认编码字符集来决定字符串的编码。


一、常用字符集

??? 1.ASCII码是7位编码,编码范围是0x00-0x7F。ASCII字符集包括英文字母、阿拉伯数字和标点符号等字符。

??? 2.GB2312是基于区位码设计的,编码范围0xA1A1-0x7E7E。GB2312字符集除常用简体汉字字符外还包括希腊字母、日文平假名及片假名字母、俄语西里尔字母等字符,未收录繁体中文汉字和一些生僻字。别名EUC-CN。

??? 可以这样理解,区位码是字符集,GB2312(EUC-CN)是对应这种字符集的编码。

??? 3.GBK是GB2312编码的超集,向下完全兼容GB2312。编码范围是0x8140-0xFEFE。别名CP936,两者差不多。

??? 注意:

??? 低字节是0x40-0x7E的GBK字符有一定特殊性,因为这些字符占用了ASCII码的位置,这样会给一些系统带来麻烦。例如 有 些系统中用0x40-0x7E中的字符(如“|”)做特殊符号,在定位这些符号时又没有判断这些符号是不是属于某个 GBK字符的低字节,这样就会造成错误判断。在支持GB2312的环境下就不存在这个问题。需要注意的是支持GBK的环境中小于0x80的某个字节未必就 是ASCII符号;另外就是最好选用小于0×40的ASCII符号做一些特殊符号,这样就可以快速定位,且不用担心是某个汉字的另一半。Big5编码中也 存在相应问题。

??? 4.Unicode是统一码,为世界每种语言的每一个字符设置唯一的二进制编码。Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。通常所说的Unicode即为UTF-16,用16位表示一个字符。容易把人搞晕的字符集和编码方式(charset/encoding),狭义的字符集,只是一个字符的集合,不包括编码方式。这里Unicode是字符集,UTF-8,UTF-16,UTF-32是编码方式。

??? 5.UTF-8是一种国际编码,通用性强。用8位表示英文,用24位表示中文。而GBK,GB2312都是用16位表示中文的。由于UTF-16不能和现行的基于ascii的编码方案兼容,所以提示出了UTF-8。UTF-8是专为Unicode设计的传输格式。它可以用来表示 Unicode 标准中的任何字元,而且其编码串流中的第一个位元组仍与 ASCII 兼容,令原来处理 ASCII 字符的软件无需或只作少量改动后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他储存或传送文字的应用中,优先采用的编码。

??? 6.ISO8859 不是一个标准,而是一系列的标准。详细说明http://baike.baidu.com/view/471161.htm

ISO8859-1,即Latin-1,是西欧常用字符,包括德法两国的字母。

二、常见用处

??? 1.在JSP页面中,在每个页面的第一行添加代码

<%@ page language="java" contentType="text/html;charset=gb2312"%>,字符集设置成GB2312

??? 2.在request,或其他JSP内置对象获取参数时,需要进行字符串转换。例如:

<%

??? String nameTemp = (String) request.getParameter("uid");

??? String name= new String(nameTemp.getBytes("iso8859-1"));

%>

??? 3.在Servlet的输出响应中,例如:

public void doGet(***){

??? request.setCharacterEncoding("gb2312");

??? response.setContentType("text/html;charset=gb2312");//一定在获取out对象之前

??? PrintWriter out = response.getWriter();

??? .......

}

??? (未整理完....)


三、配置说明

? ? 1.pageEncoding="gb2312"。JSP编译成Servlet时使用的编码。

??? 2.contentType="text/html;charset=gb2312"。指定服务器响应的编码。

??? 3.request.setCharacterEncoding("gb2312");。指定对客户端请求的编码

??? 4.response.setContentType("text/html;charset=gb2312")。指定对服务器端响应的编码

??? 注意:

??? 1.服务器按照 setCharacterEncoding->contentType->pageEncoding的顺序进行编码。

??? 2.post提交表单时,接收数据的JSP页面需要正确设置request.setCharacterEncoding。否则按照默认的ISO8859-1进行编码,即Latin-1

四、举例

??? 网上看到的这个例子不错,特引用过来。原文网址

??? 1、getBytes()

当Java程序从输入流、文件或字符文字量等途径获得字符串时,均会做字符编码的转换,例如InputStreamReader的构造函数中就需要指定编码方式,而对于从文件和字符文字量中获得字符串时,均采用系统默认的编码方式对字符数据进行解码。考虑下面一段代码:Stringstr=”中”;①byte[] bytes =str.getBytes();②bytes =str.getBytes(“ISO-8859-1”);③语句①:将一个只含有一个字符“中”的字符串文字量赋给String类的一个对象str,字符文字量“中”是按照操作系统默认编码方式进行编码,在中文windows系统中通常是“GBK”,“中”在GBK编码中是0xD6D0,在将该字符赋给str时,Java会对该字符串进行编码转换,即将GBK编码方式的“中”转换成Unicode编码方式的“中”,Unicode编码方式“中”的编码是0x4E2D,所以str在程序运行期间在内存中的二进制表示成16进制就是0x4E2D。语句②:获得str字符串的二进制形式。getBytes(Stringencoding)方法需要指定编码方式,表示获得该字符串在何种编码方式中的二进制形式。此语句中没有设置参数,表示采用操作系统默认的编码方式,即此处获得的bytes是“中”在GBK编码中的二进制形式,即bytes[0]=0xD6,bytes[1]=0xD0。

语句③:该语句与语句②的区别就是指定了编码方式,此处指定的是ISO-8859-1,即通常所说的Latin-1,该编码采用8bit对字符编码,所以编码空间中只有256个字符。该编码中只包含了基本的ASCII码和一些扩展的其它西欧字符,所以该字符集中不可能包含中文的“中”字,也就是说Java虚拟机无法在ISO-8859-1编码集中找到“中”字对应的编码,针对这种情况,就只返回一个问号(?,0x3f)字符,所以此时bytes.length只有1,且bytes[0]=0x3f

??? 2、new String(byte[] bytes, Stringencoding)

getBytes()方法从字符串获得二进制的字节数组。如果要从二进制的字节数组获得字符串,则就需要使用newString(byte[] bytes, Stringencoding)方法,该方法按照encoding编码方法对字节数组bytes中的二进制数组进行解析,生成一个新的字符串对象。byte[] bytes ={(byte)0xD6, (byte)0xD0, (byte)0x31};①String str = newString(bytes);②str = newString(bytes,”ISO-8859-1”);③语句①:定义一个字节数组。语句②:将该字节数组中的二进制数据按照默认的编码方式(GBK)编码成字符串,我们知道GBK中0xD60xD0表示“中”,0x31表示字符“1”(GBK兼容ASCII,但不兼容ISO-8859-1除ASCII之外的部分),所以str得到的值是“中1”。语句③:该句用ISO-8859-1编码方式对该字节数据进行编码,由于在ISO-8859-1编码方式中一个字节会被解析成一个字符,所以该字节数组会被解释成包含三个字符的字符串,但由于在ISO-8859-1编码方式中没有对应0xD6和0xD0的字符,所以前两个字符会产生两个问号,由于0x31在ISO-8859-1编码中对应字符“1”(ISO-8859-1也兼容ASCII),所以此语句得到str的值是“??1”。


未完待续.....


读书人网 >Web前端

热点推荐