分类: Java
2011-04-26 16:26:08
1.编辑*.java文件时发生了什么事情呢?
答:当我们用记事本编辑时,
打开紫光输入法,紫光输入法软件控制了键盘,从键盘敲击的字母变成了拼音,拼音下方显示的是GBK中的简体还是繁体取决于指定的"简体""GBK",此时上方的"yanlei"就有了下方的汉字"眼泪"而不是"眼淚".
在空格录入"眼泪"以后,表征这两个字的键盘输入文件设备缓冲区内被存入了D1BBC0E1,这是由于紫光指定了"简体GBK"进而cpu告知系统IO设备管理器得知输入的字符是简体GBK,因此I操作接收了紫光送来的D1BBC0E1进入缓冲区.键盘文件录入设备有编码集"简体GBK"
由于并行处理的机制,完成这个输入动作后,cpu得到输入IO管理器的I输入完成中断指令,cpu利马把缓冲区的内容往内存处理区中送,这个送的过程伴随着一个码转换函数的调用,就是GBK码D1BBC0E1往Unicode内存处理码FFFE3C77EA6C的转换,当cpu把缓冲区D1BBC0E1送至处理区FFFE3C77EA6C完毕,发现O操作线程提出了需要显示的处理,紧接着又调用码转换函数Unicode内存处理码FFFE3C77EA6C往屏显缓冲区GBK码D1BBC0E1的转换动作,当转换完毕,开始调度IO设备让它进行O显示操作(这里的内存处理码的转换对用户来说是透明的,用户完全可以理解"入缓冲-处理区-出缓冲"是同一个码副本)
IO设备得到cpu通知说可以取出屏显缓冲区内容进行显示了,IO取出D1BBC0E1对照字体映射字符点阵符号表进行展示"眼泪",取出D1BBC0E1这些01代码时到底按照哪个编码进行展示呢?这时屏显文件输出设备利用了系统Locale代码页也就是ANSI936 GBK代码页就行展示,根据不同的字体显示同一个中文字符的不同字符点阵符号。所以这里屏显设备也参考了编码集才能进行正确显示
键盘入缓冲GBK->内存处理unicode->屏显出缓冲GBK的一个转换(文件保存缓冲采用GBK码的一个副本), 是透明的
2.编辑好的*.java文件保存时发生了哪些事情呢?
答:编辑好的java源文件可以采用默认的GBK即ANSI936来保存文件,至于各种保存方案为什么存在以及各自的优缺点在上方的【源文件文件保存:】这里有介绍。所以在此处我们也就理解了eclipse工作空间workspace设定编码方案类似于另存为弹出窗口编码下拉框的指定
键盘入缓冲GBK->内存处理unicode->文件保存缓冲GBK的一个转换,是透明的
文件保存缓冲UTF-8的一个转换,是透明的
文件保存缓冲unicode的一个转换,是透明的
3.编译java源文件的时候发生了什么呢?
答:javac命令 javac -file.encoding xxx.java通过这个指令我们知道-file.encoding这个属性是有作用的
-file.encoding告诉JVM虚拟机是用什么编码方式保存文件的,
pageEncoding
setContentType()
setCharacterEncoding()
3.1 当我们保存java源程序文件为GBK即ANSI代码页时,取出编译时javac默认-file.encoding取的当前系统的默认文件编码方案,所以取出文件缓冲池内的"眼泪"D1BBC0E1会被正确的转换到内存处理区FFFE3C77EA6C,处理完了之后待生成*.class文件保存的时候又把内存处理区FFFE3C77EA6C转换成了UTF-8格式EFBBBFE79CBCE6B3AA保存在了*.class文件之中,因为*.class文件默认使用UTF-8保存。
动作:[GBK录入->unicode->GBK码文件缓冲(编辑时入)]====源文件怎么保存来的
||||||||||||||||
GBK码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成保存成的编码是正确的
3.2 当我们保存java源程序文件为UTF-8时(动作:GBK码D1BBC0E1->处理区FFFE3C77EA6C->UTF-8码EFBBBFE79CBCE6B3AA),取出编译时javac默认-file.encoding取的当前系统的默认文件编码GBK方案系统Locale语言指定,所以此处我们就需要进行源文件编码的指定.
3.2.1 如果我们没有重新指定的话:UTF-8格式EFBBBFE79CBCE6B3AA文件读出流的"眼泪"就会被当作是GBK编码E79C,BCE6,B3AA,造成错误,进行了GBK文件读出流->unicode处理->UTF-8码class文件保存的过程,在这个过程中GBK文件读出流发生了错误,导致以后的整个过程的错误.
动作:[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====源文件怎么保存来的
||||||||||||||||
GBK码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成GBK编码是错误的
3.2.2 如果我们指定了-file.encoding=utf-8,这时编译器就会知道源码是utf-8编码.
动作:[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====源文件怎么保存来的
||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成保存时的utf-8编码是正确的
4.执行.class文件的时候发生了什么呢?
当JVM执行.class文件时,jvm直接将保存的utf-8格式的class文件拿出来执行,进行
utf-8码class文件->内存处理unicode->处理后屏显GBK码,追加以前的从编辑开始的动作,如下:
[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====java源文件怎么保存的
||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->UTF-8码class类文件怎么编译保存的
||||||||||||||||
UTF-8码class文件->unicode->GBK码屏显 class类文件怎么执行
好:通过以上三个环节之后,我们就知道jvm虚拟机处理编码工作的原理,
在这里需要强调一下,
unicode->UTF-8码class类文件怎么编译保存的
||||||||||||||||
UTF-8码class文件读出->unicode
这个类文件的细节编码是我们不需要关心的,因为类文件的编码解码都是由JVM自动实现的,不需要本地操作系统file.encoding属性的参与的,对用户来说是透明的,所以我们可以不必考虑这层码的转换.
那么:上诉动作可以简化为:
GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====java源文件怎么保存的
|||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->->GBK屏显 class类文件怎么执行
其中GBK录入和GBK屏显都是根据系统Locale ANSI936来决定的
简化了之后我们可以看出文件的保存时编码和取出时编码是至关重要的,这里如果发生了错误,尤其是取出时编码的误认为-file.encoding=系统Locale是致命的。
针对普通Java类:
一句话总结:针对静态字符串文件以什么码保存就必需以什么码取出编译javac -file.encoding="文件保存码"
针对动态字符串,如从数据库数据文件存取内容时,数据文件什么码,rs.getString().getBytes("数据文件编码") 取出时new String(rs.getString().getBytes("数据文件编码"),"java文件保存码")
存入时new String(str.getBytes("java文件保存码"),"数据文件编码");
这里所设计都是普通的java类,那么jsp和servlet又是怎样的呢
encoding编码问题之二Jsp文件
【编辑】jsp文件windows操作开发保存时默认是按照GBK编码字符串的,可以指定保存成UTF-8等其它格式。假设以UTF-8格式保存
【上传】此时UTF-8码保存的jsp文件被转换成了UNIX系统下的iso-8859-1编码
【编译】[tomcat举例]jvm读出iso-8859-1保存jsp文件进入内存,不作任何格式的修改,交给jasper告诉它我读出好了而且文件编码格式iso-8859-1,jasper会根据指定的pageEncoding属性来决定响应内容的编码格式,当没有设置此属性时,翻译之后的_jsp.java文件为response.setContentType("text/html"),内容的编码jasper采取了默HTTP协议的传输编码格式iso-8859-1,所以我们在GBK屏显环境下看到的是乱码,(因为iso-8859-1直接高位补0进入内存处理区,结果导致两个汉字会看到四个iso-8859-1字符,gbk包含latin-1字符点阵,而进行输出缓冲待传输时又进行了简单的去高位0操作,准备传输的是默认的latin-1编码字节流)那为什么客户端反而可以看到正常的中文字符呢?
如:"眼泪"D1BBC0E1默认iso-8859-1字节四个->unicode补高位0x00D10,x00BB,0x00C0,0x00E1我们看到的乱码 ->iso-8859-1字节缓冲输出又还原到D1BBC0E1
【网络传输】经过上面的示例之后,IE端得到iso-8859-1码因为没捕获到HTTP响应头"Content-Type"也没有捕获到属性,得到的D1BBC0E1字节流会按照IE自身支持的字符集(系统Locale)来加以显示,所以反而会两两字节重组后得到正确的"眼泪"二字
=================
=================
编辑动作:GBK录入->unicode->UTF-8保存jsp文件==================
上传动作:UTF-8保存jsp文件->unicode->iso-8859-1保存jsp文件==================
编译动作:iso-8859-1保存jsp文件->unicode->iso-8859-1默认/pageEncoding属性===3
传输动作:iso-8859-1默认/pageEncoding属性->unicode->屏显GBK码===============4
观察后不难发现:
1,2环节不会有任何错误;3,4环节也不会有任何错误.
2环节后半部分、3环节上半部分是否发生文件上传转码并无影响,
因为->unicode->iso-8859-1码保存jsp文件==2
iso-8859-1码保存jsp文件->unicode==3 构成闭环,在这里不会发生任何错误。
编译动作是个关键点:它在取出jsp源文件的时候,一定要和jsp源文件保存时的编码一致,否则就会出错误.
这一点由pageEncoding="文件保存码"="Eclipse开发工具workspace工作区编码"来保证的。
1。pageEncoding=""只要设置,一定要和保存jsp文件时编码一致。
2。pageEncoding=""没有设置,注意属性,要和保存jsp文件时编码一致。
3。如果既没有pageEncoding="",也没有属性, 那么是默认的iso-8859-1对于Tomcat进行jasper编译的时候来说。而对于webSphere来说,一定会默认的在jsp或者servlet传输时默认指定content-type头部为iso-8859-1,所以这里的页面不在有任何的效果
以上分析了jsp页面中不读取动态字符串,静态字符串的展示原理,那么针对访问数据库数据文件的动态字符串的生成又是什么样子呢?这个可以参考上方的【数据库数据文件读取:】来理解。只是需要注意,从数据库取出的动态字符串必需和jsp文件保存时[既是pageEncoding=""]的编码一致,
如:pageEncoding="utf-8",那么new String(rs.getString().getBytes("iso-8859-1"),"utf-8");
pageEncoding属性告之IE浏览器什么编码方式保存的静态字符串,IE好根据此来逆向解释往->unicode内存码转换
pageEncoding = "jsp文件保存码" = "Eclipse开发环境workspace工作区编码"
new String(rs.getString().getBytes("数据文件码"),"jsp文件保存码");
tomcat服务器在jasper解释开始解释jsp源文件的时候,是根据pageEncoding属性指定的码集进行网卡缓冲待输出字节流.如果未指定,则按照默认的iso-8859-1码流输出
jsp本质上来说就是servlet
【编辑】当我们在windows环境本地编辑MyServlet.java文件时,采用的内容编码方案默认是系统Locale ANSI936即GBK编码录入,
此时
【编译】
当我们本地编译servlet时,javac -file.encoding="文件保存码"|"系统Locale默认GBK码" MyServlet.java时,这里需要确保-file.encoding="文件保存码",
[这一点是开发工具保证的,"Eclipse开发环境workspace工作区编码"="Myservlet.java源文件编码",当取出编译时Eclipse保证了-file.encoding="文件保存码"],编译好之后的*.class文件保存为UTF-8编码
【上传】当/WEB-INF/classes/*.class类文件传至任何操作系统之上时仍然是UTF-8编码。
【执行】jvm虚拟机解读classes文件,->unicode->setContentType("text/html;charset='文件保存码'")传输至IE端。如果无setContentType("uft-8")方法时,Tomcat默认准备iso-8859-1输出流传至IE端,此时发生了错误,因为原先的UTF-8码被认为成了iso-8859-1码流
new String(rs.getString().getBytes("数据文件码"),"Servlet文件保存码");
规则◎:pageEncoding = setContentType("文件保存码") = "文件保存码" = "Eclipse/workspace区编码"
规则◎◎:new String(rs.getString().getBytes("数据文件码"),"文件保存码");
以上总结了服务器端jsp文件/servlet文件本身含有的静态字符串的编码处理---规则◎:
服务器端jsp文件/servlet文件本身获取数据库动态字符串的编码处理---规则◎◎:
那么str = request.getParameter()从IE端获取的请求信息来的字符串到底是什么编码呢?
答:
IE浏览器读取系统Locale指定的ANSI代码页,通过HTTP请求头Accept-Language,并上传给Web服务器供参考。但服务器一般都忽略HTTP请求头Accept-Language,虽然有些应用程序通过读这个HTTP请求头(Accept-Language)来实现一定的国际化。
=================
post方法时:(推荐)
针对