开发者社区> 技术小胖子> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

JavaWeb开发编码与乱码总结

简介:
+关注继续查看

自我总结

1.getBytes()和new String()方法

 ▇  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,这个编码必需

  要支持中文。否则还是会出现乱码。 

2.常见字符集  

    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(浏览器提交数据时采用的字符集)。

                             这种直接修改服务器配置的方式,类似于硬编码机制,一般不用这种方法。

                            wKioL1Wvq-bzR7z4AABR_1L4Jb4749.jpg

                    方式二:逆向编解码

                            data = URLEncoder.encode(data,"iso8859-1");

                            data = URLDecoder.decode(data,"utf-8");

                    方式三:逆向编解码的简写方式

                            data = new String(data.getBytes("iso8859-1"),"utf-8");

                    当然get提交这3种解决中文乱码的方法也同样适用于post提交。




         



















转载

1.那些年JavaWeb的各种中文乱码终极解决方法

   http://www.2cto.com/kf/201209/157773.html


2.java web 开发中的乱码解决方案自我总结

    http://blog.csdn.net/baoyinwang/article/details/7457087

3.字符集和字符编码(Charset & Encoding)

    http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html

4.深入分析 Java 中的中文编码问题

    http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/



      本文转自屠夫章哥  51CTO博客,原文链接:http://blog.51cto.com/4259297/1671871,如需转载请自行联系原作者





版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
线程 - Java 多线程编程(下)
线程 - Java 多线程编程(下)
25 0
Java多线程那些事,对Java并发编程2w余字的总结,超详细(从入门到完全掌握)
Java多线程那些事,对Java并发编程2w余字的总结,超详细(从入门到完全掌握)
86 0
java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?
死锁、活锁、饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了。
71 0
五分钟带你玩转多线程(一)java多线程基础知识简介
线程概念 进程:是一个执行中的程序,如打开网易云音乐,网易云音乐就是一个进程 线程:是进程的组成,一个进程包含多个线程,是jvm最小调度单元。如网易云音乐听歌是一个线程,评价是一个线程。
53 0
21114
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载