总结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

I SO8859-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的构造函数中就需要指定编码方式,而对于从文件和字符文字量中获得字符串时,均采用系统默认的编码方式对字符数据进行解码。考虑下面一段代码:
String str=”中”;
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(String encoding)方法需要指定编码方式,表示获得该字符串在何种编码方式中的二进制形式。此语句中没有设置参数,表示采用操作系统默认的编码方式,即此处获得的 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, String encoding)

getBytes ()方法从字符串获得二进制的字节数组。如果要从二进制的字节数组获得字符串,则就需要使用new String(byte[] bytes, String encoding)方法,该方法按照encoding编码方法对字节数组bytes中的二进制数组进行解析,生成一个新的字符串对象。
byte[] bytes = {(byte)0xD6, (byte)0xD0, (byte)0x31};
String str = new String(bytes);
str = new String(bytes,”ISO-8859-1”);
语句 ①:定义一个字节数组。
语句②:将该字节数组中的二进制数据按照默认的编码方式(GBK)编码成字符串,我们知道GBK中0xD6 0xD0表示“中”,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”。


未完待续.....


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值