参考链接:
https://m.aliyun.com/yunqi/articles/548995。感谢原作者,整理的清晰明了
▇ public byte[] getBytes(Charset charset)方法
这个方法是将字符串按指定的字符集进行编码,转换成字节数组。如果不指定字符集,默认采用
系统自带的字符集。
采用不同的字符集,对于同一个带有中文的字符串,得到的字节数组的是各不相同的。因为一个
中文字符使用不同的编码方式,得到的字节长度是不同的。(可以通过将一个中文字符不同的编码转
换成字节数组,然后再打印数组的长度)
byte[] b_gbk = "中".getBytes("GBK"); //2个字节
byte[] b_utf8 = "中".getBytes("UTF-8"); //3个字节
byte[] b_iso88591 = "中".getBytes("ISO8859-1"); //1个字节
byte[] b_iso88591 = "中".getBytes("UNICODE"); //4个字节
▇ String(byte[] bytes, Charset charset)
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
。如果不指定字符集,
默认采用系统自带的字符集。
String s_gbk = new String(b_gbk,"GBK"); // 输出“中”
String s_utf8 = new String(b_utf8,"UTF-8"); // 输出“中”
String s_iso88591 = new String(b_iso88591,"ISO8859-1"); // 输出乱码
通过输出s_gbk、s_utf8和s_iso88591,会发现s_gbk和s_utf8都是"中",而只有s_iso88591是一个不被识别的字
符(可以理解为乱码),为什么使用ISO8859-1编码再组合之后,无法还原"中"字?
原因很简单,因为ISO8859-1编码的编码表根本就不包含汉字字符,当然也就无法通过"中".getBytes("ISO8859-1");来得到正确 的"中"字在ISO8859-1中的编码值了,所以,再通过new String()来还原就更是无从谈起。
因此,通过String.getBytes(String decode)方法来得到byte[]时,一定要确定decode的编码表中确实存在
String表示的码值,这样得到的byte[]数组才能正确被还原。
有时候,为了让中文字符适应某些特殊要求(如http header要求其内容必须为iso8859-1编码),可能会
通过将中文字符按照字节方式来编码的情况,如:
String s_iso88591 = new String("中".getBytes("UTF-8"),"ISO8859-1"),这样得到的s_iso8859-1
字符串实际是三个在ISO8859-1中的字符,在将这些字符传递到目的地后,目的地程序再通过相反的方式
String s_utf8 = new String(s_iso88591.getBytes("ISO8859-1"),"UTF-8")来得到正确的中文汉
字"中",这样就既保证了遵守协议规定、也支持中文。
上面这个过程的专业术语叫做逆向编解码,注意顺向编码的时候getBytes()采用utf-8,这个编码必需
要支持中文。否则还是会出现乱码。
▇ ASCII( American Standard Code for Information Interchange ):美国标准信息交换码基本的 ASCII 字符集共有 128 个字 符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号等,另外还有 32 个控制字符(如回车、空格、换行等)。 ASCII码使用7位2进制数表示一个字符,7位2进制数可表示出2的7次方个字符,共128个字符。字母和数字的 ASCII 码的记忆 是非常简单的。我们只要记住了一个字母或数字的 ASCII 码(例如记住 A 为65 , 0 的 ASCII 码为 48 ),知道相应的大小写 字母之间差 32 ,就可以推算出其余字母、数字的 ASCII码。
0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换 页)、DEL(删除)、BS(退格)、BEL(振铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等; ASCII 值为8、9、10和13分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序而对 文本显示有不同的影响。32~126(共95个)是字符(32sp是空格),其中48~57为0到9十个阿拉伯数字,65~90为26个大写英 文字母,97~122为26个小写字母,其余为一些标点符号、运算符号等。
▇ ANSI(MBCS)
为了扩充ASCII编码,以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码,又称为"MBCS(Muilti-Bytes Charecter Set,多字节字符集)"。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,所以在中文 windows下要转码成gb2312,gbk只需要把文本保存为ANSI 编码即可。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。一个很大的缺点是,同一个编码值,在不同的编码体系里代表着不同的字。这样就容易造成混乱。导致了unicode码的诞生。其中每个语言下的ANSI编码,都有一套一对一的编码转换器,Unicode变成所有编码转换的中间介质。所有的编码都有一个转换器可以转换到Unicode,而Unicode也可以转换到其他所有的编码。
▇ GB2312
GB 2312是一个简体中文字符集(详情请百度)。GB2312采用了二维矩阵编码法对所有字符进行编码,GB2312字符在计算机 中存储是以其区位码为基础的,其中汉字的区码和位码分别占一个存储单元,每个汉字占两个存储单元。由于区码和位码的取 值范围都是在1-94之间,这样的范围同西文的存储表示冲突。
▇ GBK
GB 2312的出现,基本满足了汉字的计算机处理需要,但对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致 了后来GBK及GB 18030汉字字符集的出现。GBK编码标准兼容GB2312,简、繁体字融于一库。GBK采用双字节表示,字符有 一字节和双字节编码,00–7F范围内是一位,和ASCII保持一致。
▇ Big5
大五码是一种繁体中文汉字字符集(由来请百度)
▇ Unicode
如果有一种编码,将世界上所有的符号都纳入其中,无论是英文、日文、还是中文等,大家都使用这个编码表,就不会出现编码不匹配现象。每个符号对应一个唯一的编码,乱码问题就不存在了。这就是Unicode编码。Unicode固然统一了编码方式,但是它的效率不高,比如UCS-4(Unicode的标准之一)规定用4个字节存储一个符号,那么每个英文字母前都必然有三个字节是0,这对存储和传输来说都很耗资源。(怪不得编程的时候不采用这种编码方式)
▇ UTF-8
为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。
▇ ISO-8859-1
ISO-8859-1编码是单字节编码,向下兼容ASCII,它不支持中文,只支持几乎欧洲所有国家的语言。但它的使用十分的广泛,因为大多编程软件都是由外国人制作的。
▇ Base64
一端发送GB2312编码->根据Base64规则->转换成ASCII码,接收端收到ASCII码->根据Base64规则->还原到GB2312编码。
3.Web打印中文数据和提交中文数据乱码问题(服务用的是tomcat)
不管是从服务器向客户端打印数据,还是从客户端向服务器提交数据。数据的交互传输都是以流的方式进行的
1)提交中文数据
在服务器端,可以通过request.getParameter()方法得到某一个表单数据,实际客户端传输的是按浏览器默
认字符集编码之后的字节数据(表单数据.getBytes(浏览器默认字符编码)),数据到达了tomcat服务器,
tomcat默认使用iso8859-1字符集来解码表单提交过来的字节数据,即执行new String(客户端提交的byte[]数
组,tomcat默认解码字符集)。
>>对于post提交,数据会先放到request缓冲区中,由于request缓冲区的默认字符集(iso8859-1)是可以进
行修改的,通过request.setCharacterEncoding(decode)方法,那么tomcat在解码的时候就会按照指定字符集来
解码。
例子:一般浏览器的默认编码字符集是utf-8,用post提交中文数据,会向服务器发送字节数组,“中文”.getBytes("utf-8");在 服务器端设置request.setCharacterEncoding("utf-8")。那么服务器通过 request.getParameter()得到的字符串就是new String("中文“.getBytes("utf-8"),"utf-8"),编解码方式一致,自然不会出现中文乱码的情况了。
>>对于get提交,数据不会放到request缓冲区中,所以无法修改tomcat解码的默认字符集iso8859-1,那么通过 request.getParameter()方法得到字符串就是乱码了。
例子:一般浏览器的默认编码字符集是utf-8,用post提交中文数据,会向服务器发送字节数组,“中
文”.getBytes("utf-8");那么服务器通过request.getParameter()得到的字符串就是new String("中
文“.getBytes("utf-8"),"iso8859-1"),编解码方式不一致,肯定就乱码了。
那么,应该如何解决get提交中文乱码的问题呢?
方式一:修改tomcat的server.xml文件,将URLEncoding改为utf-8(浏览器提交数据时采用的字符集)。
这种直接修改服务器配置的方式,类似于硬编码机制,一般不用这种方法。
方式二:逆向编解码
data = URLEncoder.encode(data,"iso8859-1");
data = URLDecoder.decode(data,"utf-8");
方式三:逆向编解码的简写方式
data = new String(data.getBytes("iso8859-1"),"utf-8");
当然get提交这3种解决中文乱码的方法也同样适用于post提交。