`
四眼蛤蟆
  • 浏览: 97654 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java字符编码原理解析

    博客分类:
  • Java
阅读更多

什么是字符,什么是字节?

可以理解为计算机没有字符的概念,只有字节。字符是存在于人类语言层的概念,其作用是为了人与人之间的交流,因为字节对于人类是不可读的,但是计算机存储所有的数据都是按照字节存储。
因 此要将人类意识中的字符存储到计算机中,则必须将字符转换为字节数据,那么怎么转化呢,则必须要一种映射规则,这里的映射规则就是通常意义中的字符编码, 比如说该文件是GBK编码,可以说为:这个文档中的字符数据是按照GBK这种字符字节映射规则将字符转换为字节存储的。

所以所有要将人类意识中的字符存储在计算机或者需要通过计算机传递时,都涉及到字符和字节之间的通过某种映射规则的转换。

将字符按照映射规则转化为字节称为编码,反之称为解码。

弄明白了字符和字节,以及为什么要编码解码的意义,在看在java中哪些地方需要编码:

1:java的源代码文件.我们在使用编辑器编辑数据后,需要将编辑器中的”字符们“存储起来时,需要选择一种映射规则存储在计算机中。当编译 java源代码时,javac读取源代码文件,得到源代码文件的字节数据后,需要将其转换为字符,那么就必须按照刚刚存储源代码时选择的映射规则同样的
映射规则才能将这些字节正确还原为人类意识中的字符,然后再将这些字符使用utf-16映射规则映射为字节存储在.class中。所以在编译java源代码时,必须指定源代码的字符字节映射规则(编码),如果指定错了,那么映射回来的字符就会出错。
注:javac默认采用本地编译平台的编码读取源代码文件。所以如果开发团队中有些人是日文系统,有些是中文系统,但是又没有统一源代码编码,上传到cvs后,后来又在utf-8上编译,呵呵,全乱了。

2:控制台的编码:当我们在java代码中使用System.out.println();输出字符时,向操作系统传递数据,让操作系统再显示出 来。这中间也存在编码。记住:所有涉及字符的地方都涉及编码。因为底层都是通过字节传递的,要通过字节传递就必须选择一种字符字节映射规则。
  试想在java端我们采用一种映射方式将字符映射为字节,将这些字节发送给操作系统,操作系统得到字节数据,然后再使用某种映射方式将字节映射回字符。如果采用的映射方式不对也就会产生显示出不可预测的数据,不是用户希望的结果,这就是乱码
  而java实现的时候是采用的本地操作系统默认的映射方式将字符映射为字节,操作系统也是采用默认的将字节映射回字符,因此这个过程中是不会出现任何错误的。那么我们在控制台看见的乱码是因为在java内存中还是字符时这个时候这个字符就已经不是你所希望看见的了。
  如上面说的源代码编码,如果编译的时候指定编码错误,那么将源代码字节映射为字符就已经出错,然后将错误的字符采用utf-16映射为了字节,运行的时候 再将这些字节映射为字符,这个时候的字符就已经是错的了(这个字符是本来是utf-16映射规则映射成的字节但是后来又按照gbk映射
  规则映射成的字符。和控制台出现乱码容易混淆的情况是远程控制的时候如使用ssh,因为这个时候又多了一层ssh服务端向ssh客户端发送将字符按照某种映射规则映射成的字节数据和ssh客户端选取一种映射规则将字节映射为字符的情况。
  
3:JSP 文件的编码。在JSP中使用pageEncoding指定jsp源文件的编码。原理和上面第一条中的java源代码一样。但是为什么jsp需要 而.java文件不需要呢。因为jsp是在服务器上编译的。你在本地机上写jsp文件,存储的为默认编码GBK,到服务器上以后万一服务器为utf-8编 码,如果采用和.java一样的策略不是就会出错了吗。


4:web服务端向浏览器发送数据:因为要通过网络传递字符数据,所以需要将字符按照某种方式映射为字节,在浏览器端,浏览器接收到字节数据再选取某种映射方式反映射为字符供用户观看。同样,如果选取的影射方式不匹配就会出错。所以可以让服务器将编码方式告诉客户端。在HTTP的报文头中可以包含这些信息(如Content-Type: text/html;charset=GBK),这可以通过response.setContentType实现(在jsp中使用<%@ page contentType=""%>指令将转化为response.setContentType代码)。如果在jsp中指定了 pageEncoding但是没有指定contentType,生成的servlet代码中默认使用pageEncoding的编码设置 contentType.如果没有设定contentType服务器(tomcat)默认设定为iso-8859-1。

5:浏览器向服务器发送的数据(和浏览器以及浏览器的配置相关):同样也要通过网络传输。所以需要知道客户端采用的是什么映射规则将用户输入的字符 映射为字节传递给服务端.客户端一般采用的是该页面的编码发送数据(这个我没有认真测试过),但是web服务器(tomcat)确是默认采用iso- 8859-1映射规则,所以双方的映射规则不一致。解决方案就是
 request.setCharacterEncoding设置服务器针对浏览 器发送来的字节数据的映射规则(不同的服务器该方法实现策略可能不一样,在项目中遇到过weblogic和tomcat不一样,weblogic该方法会 将HTTP头和内容块数据都采用该方法的参数设置映射规则,但是在tomcat中该映射规则只用于内容块,而报文头的映射规则在server.xml的 connector的URIEncoding配置).
 不同的浏览器可能也存在不同。我在IE6中测试服务器发送utf-8的编码,通过抓包发现 服务器发送下来的数据的确是utf-8的,但是如果通过url传递如<a href="1.jsp?a=趁"/>结果发现IE传递的是e8,b6(少了一个字节),而"趁"的utf-8编码是e8,b6,81。但是如果通 过form提交,不管是用get/post方法,传递的都是"%e8,%b6,%81"
 这种以“%”开始的编码是将二进制使用十六进制表示。但是在opera中,上面的三种方法都传递的是"%e8,%b6,%81".那么如果服务器发送的是gbk编码呢?呵呵自己测试试

6:javascript编码:javascript和浏览器也有关系,IE中,如使用XMLHTTPRequest的open方法调用 open("GET", "2.jsp?a=人");虽然当前页面是utf-8编码,但是javascript传递的是c8cb,这是"人"的gbk编码。而在opera中传递的 是%E4%BA%BA,是正确的.如果服务器发送的字节是utf-16编码,IE中仍然传递的是"人"的gbk编码,opera也仍然传递的是utf-8 的编码。
  不知道浏览器是不是可以在哪儿配置

7:数据库编码:数据库不好测试,因为还涉及到数据库客户端编码的问题。如果将正确的字符按照数据库指定的编码存储在数据库文件中,当查询数据时, 数据库服务器将正确的字符发送给了客户端,但是客户端字符字节映射规则如果设置错误,可能会导致用户错误地认为数据库中存储的是错误的字符。最好的办法是 抓包分析,但是数据库协议非常复杂,又无法抓包,
  但是如果在某个过程中发生了出错,原理和上面描述的一样,一定是浏览器<->web服务器,web服务器<->数据库,数据库<->数据库客户端,ssh客户端<->ssh服务端等等之间某个地方出现了问题。 
  

要解决双方选择的字符字节映射规则不一致而导致的乱码问题:
1:是告诉对方自己采用的什么映射规则将字符转换为字节的
2:用协议约定,约定双方都用某个规则映射
3:类似于XML在第一行标志下面的数据是采用什么映射规则映射的
4:在文件头存储特殊字节标志映射规则,如windows处理utf-16(会导致如果"联通"两个字出现在文件开始的话出现问题,大家可以到网上搜索一下这个情况,分析分析,呵呵)

 

分享到:
评论

相关推荐

    java源码包---java 源码 大量 实例

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目源代码

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包4

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包3

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包2

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,...

    Java语言基础下载

    Java编码约定 56 运算符的优先级 58 升级和表达式的类型转换 62 独立实践 70 第五章:数组 71 学习目标 71 数组的描述 72 创建数组 72 多维数组 78 拷贝数组 80 内容总结 83 独立实践 84 第六章:继承 86 学习目标:...

    java面试题

    84.2. 我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 106 84.3. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。以下程序使用...

    Java面试宝典-经典

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    java面试宝典

    55、编码转换:怎样将GB2312 编码的字符串转换为ISO-8859-1 编码的字符串? 14 56、写一个函数,要求输入一个字符串和一个字符长度,对该字符串进行分隔。 14 59、Java 编程,打印昨天的当前时刻。 15 60、java 和...

    Java面试宝典2010版

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    java面试题大全(2012版)

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    java 面试题 总结

    JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变...

    Java Web编程宝典-十年典藏版.pdf.part2(共2个)

    5.4.5 实现字符编码过滤器 5.5 实战检验 5.5.1 通过Servlet实现录入用户信息 5.5.2 应用过滤器实现网页计数器 5.6 疑难解惑 5.6.1 访问Servlet出现404错误 5.6.2 修改Servlet无效 5.6.3 创建过滤器并没有实现过滤...

    最新Java面试宝典pdf版

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    Java面试笔试资料大全

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    java面试宝典2012

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 98 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

Global site tag (gtag.js) - Google Analytics