编码

来源:互联网 发布:电子磅软件 编辑:程序博客网 时间:2024/04/29 05:11

一:java 编码
java 数据类型
1.整型
Java定义了4个整型类型:byte、short、int、long,且它们都是有符号的正负值。java不支持无符号的正整数。下表列出了这4中类型的编码方式、数据宽度和其表示范围。
数据类型       编码方式        所占位数        范围                   说明
byte            补码              8                  -128~127        最小的整数类型是字节(byte),有符号8    

                                                                                   位 类型。
short          补码              16                -32768~32767
int              补码               32                -2147483648~2147483647  long 补码 64
2.字符
与C/C++不同,Java语言使用Unicode字符集来定义字符类型,即使用16位无符号整数来表示一个字符。Unicode字符集定义了人类语言中出现的

所有字符,是很多字符集的集合。在Java中,char的范围是从0~65536 ,而我们熟悉的ASCII标准字符集的范围是从0~127,扩展的8位字符集也只是0~255。

     总结一些自己关于编码方面的心得,汇集网上众多关于此的帖子资料,已被日后查询只用。
首先好像Jole讲过这样一句话,大意是:当面对一串字节流的时候,如果不指定它的编码,其实际意义是无法知道的。
这句话应该也是我们面对"字符转字节,字节转字符"问题时,时刻应牢记的。否则乱码问题可能就接踵而至。
其实乱码问题的本质就是Encoding和Decoding用的不是一个编码,明白了这个道理就很好解决乱码问题了。
  Java中常见的时候有如下:
    1. String类使用byte[]的构造函数 String(byte[] bytes),String类同时提供了两个重载
        String(byte[] bytes, Charset charset)
        String(byte[] bytes, String charsetName)
    通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。
    2. String类的getBytes函数 byte[] getBytes() 同样有如下两个重载:
         byte[] getBytes(Charset charset)

         byte[] getBytes(String charsetName)

    使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
    3. PrintStream的 print(String s)同样设计到这个问题,为此PrintStream的构造函数中除了PrintStream(File file),还有PrintStream(File file, String csn) 否则the string's characters are converted into bytes according to the platform's default character encoding, DataOutputStream构造时没有方法指定编码,但其提供了一个writeUTF(String str)未指定编码的都是使用the platform's default charset, 可使用System.getProperty("file.encoding"),Charset.defaultCharset()获得。但经我测试都是依赖于你运行此代码的Java源文件编码,如Java源文件编码为UTF-8 ,则 System.getProperty("file.encoding") 输出为UTF-8 ,而如果为GB2312,则输出为

GB2312。
一个问题,java的文件编码是什么?生成的class文件编码是什么,探讨一下下面这个例子:
例如:
有java 源文件:
public class EncodingTest {
    public static void main(String[] args) {
        String s = "哈";
        String des = "";
        try {
            System.out.println("默认编码:"+System.getProperty("file.encoding"));
            des = new String(s.getBytes(), "GB2312");
            System.out.println("String : GB2312 =" + des);
            String s_string1 = new String(s.getBytes(), "UTF-8");
            System.out.println("String : UTF-8 =" + s_string1);
        } catch (Exception ex) { }
     }
}
如果EncodingTest.java的编码是GB2312,则输出结果是:
默认编码:GB2312
String : GB2312 =哈
String : UTF-8 =
如果EncodingTest.java的编码是UTF-8,则输出结果是:
默认编码:UTF-8 
String : GB2312 =?
String : UTF-8 =哈
      
解释:
首先java源文件是按照默认编码(而它的默认编码就是保存时使用的编码,我认为是这样的。)以byte stream的方式存储在硬盘上的。
例:
如果Editor(编辑器)把*.java存成GBK或GB2312文件编码,这个"哈"存在硬盘上的byte stream是两个byte,B9 FE,(查询GBK编码表知道 "哈"的十六进制编码表示正是B9 FE)。如果Editor把java存成UTF-8文件编码,这个"哈"存在硬盘上的byte stream是两个byte,54 C8,也就是以Unicode码存储。(顺便提一下,"哈" 的Unicode码是54 C8,UTF-8 是E5 93 88)。所有unicode char 都是两个字节(也有四字节的,Unicode 3.1增加了一个B扩展区,编码进入四字节。编码空间约为21亿

从 hē 到 xiāo ,共增加了42711个四字节东亚表意文字目前计算机中实际可使用70269个东亚表意文字(27558+42711)。Java string 在内存里不是按UTF-8编码的,只有生成了class文件,代码里的string literal才是按UTF-8编码存的。由于UTF-8是变长的,所以那个字可能是1 byte, 2 bytes 或3 bytes。


关于UTF-8编码的。
http://forum.javaeye.com/viewtopic.php?t=21684


下面是了解编码和字节码的关系。
byte[] bytes = "中".getBytes("GBK");
按照GBK编码表中字的编码为 D6 DO,用上面方法取得字节数组时,它的值为 bytes[0] = -42,bytes[1] = -48 。这两个值和GBK编码表的D6 D0
有什么关系?答案是:我们说过byte的取值范围是-128 ~ 127,大于127的数值都会变为负数。如果是负数就+256变成正确的值。再将这个值转换成16进制,就是上面的D6 D0了。
在程序员观点下,有字符和字节两个概念,但它们之间并没有直接的对应关系,只有在指定了一种特定的编码方式(比如GB2312)后,才会有一定的对应关系。举例来说,一个中文字符,在GB2312的编码方式下对应两个字节,在UTF-8编码方式下对应三个字节,而在UCS2编码方式下对应两个 字节;而对于标准 ASCII 字符来说,在GB2312和UTF-8 编码方式下对应一个字节,在UCS2编码方式下对应两个字节。
有如有源码片段:
byte[]   b   =   new   byte[]{-128, 0, -64, 0, -32, 0}; 
String   s   =   new   String(b); 
字符串的编码、解码过程不是完全可逆的。不同的编码方案都有数据转换时的盲区。
对于你举的例子来说,由于GBK编码只对连续的两个小于0的字节才识别为汉字,
所以,类似-128,0这样的字节序列,对于GBK是不可识别的,转换后为字符'?',结果也就是63 ,把-128换成其他的负数,结果也是一样的。要保持原字节的内容,要采用“ISO8859_1”。
修改后的代码如下: 
  byte[]   b   =   new   byte[]   { -128,   0,   -64,   0,   -32,   0  };
  String   s   =   new   String(b,"ISO8859_1");
  byte[]   c   =   s.getBytes("ISO8859_1");
  for   (int   i   =   0,   j   =   b.length;   i   <   j;   i++)   { 
          System.out.println(b[i]   +   "/t"   +   c[i]);
  }
这也就:如果EncodingTest.java的编码是GB2312,则输出结果是:String : GB2312 =哈:s.getBytes()通过使用默认的GB2312(因为 EncodingTest.java的编码是GB2312) 解码指定的 byte 数组为:bytes[-71,-2],-71 + 256 = 185(十进制),对应B9(十六进制),-2 + 256 = 254(十进制),对应FE(十六进制)。
                          
生成的class文件编码是什么?
                        
javac首先看有没有-encoding这个开关,如果有,就按这个开关指定的encoding去解码,如果没有,就按系统省却的encoding去解码,
这个系统encoding设置在file.encoding这个property里面。
Java是使用Unicode字符集的,意思是在内存运行的时候是这样的。当Java源程序被编译为.class文件的时候,是以UTF-8字符集存储字符的。
比如字符串"汉语"的Unicode字符为:0x49 6C ED 8B。在.class文件中则变成了:0xE6 B1 89 E8 AF AD。实际上如果用以下程序输出 
"汉语"二个字的16进制字节序列:
        String str = "汉语"; 
        try{byte[] b = str.getBytes("Unicode");
        for(int i : b){   
         System.out.println(Integer.toHexString(i));
        } 
        }catch(Exception ex){ex.printStackTrace();  }
会发现,实际输出的是 0xFE FF 6C 49 8B ED。多出来的0xFE FF,是Unicode字符串的BOM(Byte Order Mark)。但是为什么输出的顺序 
(0xFE FF 6C 49 8B ED)和文件中的顺序不一致(0xFF FE 49 6C ED 8B)?
public byte[] getBytes(Charset charset) 使用指定的字符集将此 String 解码为字节序列,并将结果存储到一个新的字节数组中。
如果不指定参数,则使用系统默认的字符集,对于简体中文系统一般为GBK。
                                        
有一servlet UnitePlanServlet.java
public class UnitePlanServlet extends  HttpServlet {
    static final private String CONTENT_TYPE = "text/html; charset=GBK";
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
                                                        throws ServletException, IOException {
          doPost(req, resp); 
    } 
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                                                        throws ServletException, IOException {
         doAction(req, resp);
    } 
    private void doAction(HttpServletRequest req, HttpServletResponse resp) 
                                                        throws ServletException, IOException {
          try {
               String st = "哈";
               System.out.println("默认编码:"+System.getProperty("file.encoding")); 
               String des=new String(st.getBytes(),"GB2312");
               System.out.println("String : GB2312 =" +des); 
                                            
               String s_string1 = new String(st.getBytes(),"UTF-8"); 
               System.out.println("String : UTF-8 =" +s_string1); 
                                                          
               RequestDispatcher rd = getServletContext().getRequestDispatcher("/myplan.jsp");
              rd.forward(req, resp);  
                     
           } catch (Throwable e) {}            
    }
}
web.xml 片段:
<servlet>   
<servlet-name>UnitePlanServlet</servlet-name>
<display-name>UnitePlanServlet</display-name>
<description></description>
<servlet-class>servlet.UnitePlanServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UnitePlanServlet</servlet-name>
<url-pattern>/servlet/unitePlan</url-pattern>
</servlet-mapping>

一个jsp myplan.jsp
<%@ page contentType="text/html; charset=GBK"%>
<html>
<head>
<title>无标题文档</title>
<script>
function mergeItem(){
  window.location.href="<%=request.getContextPath()%>/servlet/unitePlan";
}
</script> 
</head> 
<body>
<input onclick="mergeItem();"  type="button" value="查看" name="noregis6" />  
</body>
</html>           
点击"查看"按钮调用servlet UnitePlanServlet.java ,
如果UnitePlanServlet.java 编码是GB2312,输出结果:
默认编码:UTF-8

String : GB2312 =?
String : UTF-8 =哈
如果UnitePlanServlet.java 编码是UTF-8,输出结果:

默认编码:UTF-8
String : GB2312 =?
String : UTF-8 =哈
也就是和源文件UnitePlanServlet.java的编码没关系。因为jsp实际调用的是UnitePlanServlet.class,上面我们说过当Java源程序被编译为.class文件的时候,是以UTF-8字符集存储字符的,也就是*.class(字节码文件)的编码方式是UTF-8。

二:jsp编码 

(一)jsp中影响编码的属性及其设置小结(contentType,pageEncoding,charset,setCharacterEncoding)2008-03-19 22:451. 名词解释及其作用
    1. contentType: <%@ page contentType="text/html; charset=UTF-8"%>
    2. pageEncoding:<%@ page pageEncoding="UTF-8"%>
    3. html页面charset:<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    4. setCharacterEncoding:request.setCharacterEncoding(),response.setCharacterEncoding()
    5. setContentType:response.setContentType()
    6. setHeader: response.setHeader()
    7. jsp页面编码: jsp文件本身的编码
    8. web页面显示编码:jsp的输出流在浏览器中显示的编码
    9. web页面输入编码: 输入框输入的字体编码
    10. web服务器输入的请求流: web Server相应浏览器的请求数据
    11. web服务器输出的响应流: web Server相应浏览器的输出数据
2. 他们之间的相互影响和作用域,以及先后作用顺序
    1. pageEncoding: 只是指明了 JSP 页面本身的编码格式,跟页面显示的编码没有关系;
    容器在读取(文件)或者(数据库)或者(字符串常量)时将起转化为内部使用的 Unicode,而页面显示的时候将内部的Unicode转换为contentType指定的编码后显示页面内容;
    如果pageEncoding属性存在,那么JSP页面的字符编码方式就由pageEncoding决定,否则就由contentType属性中的charset决定,如果charset也不存在,JSP页面的字符编码方式就采用默认的ISO-8859-1。
    2. contentType: 指定了MIME类型和JSP页面回应时的字符编码方式。MIME类型的默认值是“text/html”;字符编码方式的默认值是“ISO-8859-1”. MIME类型和字符编码方式由分号隔开;
    3. pageEncoding和contentType的关系:
        1. pageEncoding的内容只是用于jsp输出时的编码,不会作为header发出去的; 是告诉web Server,jsp页面按照什么编码输出,即web服务器输出的响应流的编码;
       2. 第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java).无论pageEncoding指定是
UTF-8,还是GB2312,最终翻译成德java源码的编码方式都是UTF-8。
       3. 第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码.JAVAC用
UTF-8的encoding读取java源码,编译成UTF-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范.
       4. 第三阶段是Tomcat(或其的application container)载入和执行 “阶段二” 来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段
二的参数contentType就发挥了功效  
    4. 和contentType效果一样的设置方式还有 html页面charset, response.setCharacterEncoding(),response.setContentType(),response.setHeader();
response.setContentType(),response.setHeader();优先级最好,其次是response.setCharacterEncoding();再者是<%@page contentType="text/html; chareset=gbk"%>,
最后是<meta http-equiv="content-type"content="text/html; charset=gb2312" />.
    5. web页面输入编码: 在设置页面编码<%@page contentType="text/html; chareset=gbk"%>的同时,也就指定了页面的输入编码;如果页面的显示被设置为UTF-8,
那么用户所有的页面输入都会按照 UTF-8 编码; 服务器端程序在读取表单输入之前要设定输入编码;表单被提交后,浏览器会将表单字段值转换为指定字符集对应的字节值,然后根据 HTTP 标准 URL编码方案对结果字节进行编码.但是页面需要告诉服务器当前页面的编码方式;request.setCharacterEncoding(),能修改Serverlet获取请求的编码,response.setCharacterEncoding(),能修改Serverlet返回结果的编码。

 

(二)jsp中文问题 QA (回答的可能有些不准确) -------网上帖子收集。

1 第一步,程序员用编辑工具编写jsp文件,然后保存。此时如果不特别指定,一般都是以平台的默认编码保存的。比如在中文win2k上,这个jsp文件是以GBK编码的。   

回答:jsp文件就是文本文件,保存得编码与你使用得编辑器相关,在jbuilder里边如果你把系统编码设置为gbk,jsp默认会用gbk保存。而在eclipse里边,则是按照jsp
规范中指定得,如果页面没有指定编码规则,则页面是iso8859-1,jsp文件就是文本文件,保存得编码与你使用得编辑器相关,在jbuilder 里边如果你把系统编码设置为
gbk,jsp默认会用gbk保存。 而在eclipse里边,则是按照jsp规范中指定得,如果页面没有指定编码规则, 则页面是iso8859-1,所以一个含有中文得文件,如果未指定
编码,eclipse 保存后汉字全部变成问号。当然也可以手工指定每个文件的编码。
2 . web容器将jsp文件编译为servlet class文件。编译器需要读取硬盘上的jsp文件,那么它以什么字符集来解码呢?这个过程就像我们编辑一个文本文件,然后保存(是GBK编码),你再用编辑器打开时,编辑器会以GBK来解码一样。不过这里还是复杂一点,jsp编译器根据什么来确定解码字符集?是< %@page pageEncoding="GB2312"% >么?那么当2个页面指定的 pageEncoding不同并且用include将其合在一起时,jsp编译器的策略是什么?


回答:

       web容器首先将jsp页面转换成servlet的java文件,对于每个jsp页面,按照jsp的规范,其编码的确定有大概4个步骤,指定了pageEncoding的最优先,还可以在配
置文件中指定编码,很多种方式,我觉得指定pageEncoding最方便。如果不指定,默认的是iso8859-1而不是系统的默认编码。jsp规范是这样规定的,但是不同的web容
器对于规范的实现上稍有差别。但是一般来说,指定了pageEncoding之后,不会出现问题。web容器转换得到的java文件的编码——只有一个,UTF-8。

3. 浏览器以get或post方法传递参数时,是以什么编码的?是否UTF-8?以get传递时还要经过urlencoding,除此之外和post方法还有何不同?看车东的文章
http://www.chedong.com/tech/hello_unicode.html,get传递时,是先按GBK编码再urlencoding,我自己试验的结果也是如此。那么设定浏览器以UTF-8发送还有什么作
用?另外,如果是这样,那么web容器怎么知道按什么来解码?因为客户端可是多种多样阿,传过来的参数什么编码的都有,web容器怎么处理?

 

4. web容器得到浏览器传递的参数,以什么字符集解码?若浏览器以UTF-8编码,这里只能是UTF-8,如果浏览器以平台字符集编码,那么这里web容器是怎样成功解码的
呢?成功解码后,将参数写进request对象里时又是什么编码?默认ISO-8859-1?从request里取得的参数是以什么来解码?通过request.setCharacterEncoding("GB2312")
指定?

3和4 的回答:

        对于get/post的编码问题,这应该是http协议中的内容吧,研究的不多。说说自己的经验。对于post,发送和服务器端处理都是按照html的编码来进行的。所以gbk的页面
发送过去,用request.setCharacterEncoding("GBK")即可得到正确的内容。但是注意,这个函数的调用必须在所有 request.getParameter的调用之前才有效。 对于get,
浏览器发送的时候,对字符应该是按照html页面的编码进行url 的编码。而在服务器端,我没有研究jsp规范中是否有规定,只知道在tomcat 中,如果不进行配置,那么
url编码的默认编码规则tomcat会认为是 iso8859-1,但是实际发送过来的是html页面中的编码的urlencoding,所以会导致乱码。tomcat中可以设置
useBodyEncodingForURI="true"来 解决这个问题。我记得有另一个属性可以指定url的编码,是URIEncoding吧。召唤达人对get进行详细介绍。

5. servlet从request里取得信息,并进行一些操作后,往response的输出流里写入信息时又是什么编码?web容器从response输出流里读取时怎样解码?然后以什么字符
集编码发送到客户端浏览器?默认ISO-8859-1?通过response.setContentType("text/html;charset=GB2312")指定?当2个页面通过include合在一起怎么办?

 

回答:

       一个页面(包括其include 的文件),其contentType只能被指定一次 (用<  %@page .. %  >指定),但是有些服务器检查不严格,可能可以指定多次。其输出的编码当然
是这个指定的编码了。对于包含,只需要在页首加上pageEncoding即可,参考2。

可能有疏漏或错误,大家多指点或补充。注:提到jsp规范,都是指jsp2.0规范。可以从sun的网站下载。

 

6. 浏览器根据本地编码将信息发送给服务器端,服务器端怎样解码?是读取http头信息accept language么?  成功解码后,构造request对象时,用什么编码?包括再从
request里取信息。 我的想法是通过request.setCharacterEncoding("GB2312")指定,response同此理。我想web容器总要经过解码-编码-构造request对象的处理过程,不
知道对不对。   

 

回答:

       html页面的meta信息中有页面的编码信息 request对象的解码取决request.setCharacterEncoding,所以web容器并不需要进行解码,解码可以在读取request中内容的时候再解,response的解码过程,就是一个字符流的写入过程,写入的字符流是什么编码决定contentType中的charset 所以,web容器对页面内容不需要做编码、解码的工作。要说编码解码也就是对url请求进行解码而已 。web容器一开始从客户端取得的一定是经过编码的字节流对不对?然后不管怎样,它要把这些信息放进request对象。再然后,通过request. getParameter()取得信息。 web容器取得字节流后,根本不进行解码,直到request. getParameter()时才根据request.setCharacterEncoding()的设置进行解码在这时才完成字节流到java String的转换,这时又要分时get请求,还是post请求setCharacterEncoding()用来设置http请求或者相应的编码。对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,需要进一步处理。参见下述 "表单输入"。值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。java doc上说明:This method must be called prior to reading request parameters
or reading input using getReader()。而且,该指定只对POST方法有效,对GET方法无效。分析原因,应该是在执行第一个getParameter()的时候, java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析所有的提交内容,setCharacterEncoding()自然就无效。对于response,则是指定输出内容的编码,同时,该设置会传递给浏览器,告诉浏览器输出内容所采用的编码。 (更多内容见java encoding参考 )不知道你用的是不是tomcat容器,如果是的话,就如以下:

我说的问题是为什么get只能用用字节转换处理。这是因为tomcat4.x和tomcat5.x不太一样了。如果你用4.x的话,应该不会出现这样的问题。因为到了tomcat5.x后,它把get和post提交分开来处理了。post和原来是一样的所以用Filter类就可以了。但是get的方式必须用String des=new String(s.getBytes("iso8859-1"),"GBK。而且字符集也必须是iso8859-1,因为get默认的字符集是这样的。 (Jsp页面URL中传递参数是一种GET请求,如超链接。Form表单提交时POST请求。)还有一种办法就改tomcat的server.xml文件,如下:

Java代码

< Connector port="80"   maxThreads="150"   minSpareThreads="25"   maxSpareThreads="75"   enableLookups ="false"  redirectPort="8443"  acceptCount="100" debug="0"  connectionTimeout="20000" disableUploadTimeout ="true"   URIEncoding ="GBK"  />  

修改后只要字符编码都设成统一的话,就不用转了。

而我原来想的是:web容器取得字节流后,马上进行解码,转成某种编码的字符流,再将此字符流转成字节流写进request对象中。这样request. getParameter()时当然就又要解码了,原来不是这样的。

 

举个例子说明指定编码的必要:
     如果一个网页指定编码为utf-8, <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />, 页面上有一个form,提交到一个servlet,那么用户
输入的字符传过来的字节流就是按指定编码encoding的,例如你输入了"Hello你好",如果是utf-8,那么传过来的就是如下:

         [104, 101, 108, 108, 111, -28, -67, -96, -27, -91, -67]
 我们看到后面汉字每个用了3个字节,这个可以参考Utf-8的相关知识。但如果你页面指定的是GBK,那传过来的就不一样了:
 [104, 101, 108, 108, 111, -60, -29, -70, -61]
所以servlet端,当使用request.getParameter的时候内部应该是调用String s = new String(bytes, response.getEncoding())的,如果你的response没有设置编码,
那么就采用默认的编码(tomcat是ISO-8859-1),不会会转为java 平台的GBK,那中文就变成乱码了。 所以为了避免乱码,jsp站点一般设一个过滤器,所有的页面、servet都设置统一的编码。设置 response.setEncoding, request.setEncoding。

Java的String内部是一个char[], char是一个用16位存储的utf-16编码的单元。为此,当要把字符、字符串转为字节输出到文件、网络,或者从文件、网络读到的字节流还原为有实际意义的字符,都要明白其编码是什么。讨论JSP转为servlet的问题,不要把这个问题和浏览器与Servlet Container之间通讯时的乱码问题混在一起. 我把讨论局限于Tomcat 5.5, 发布模式是jsp文件写好了之后直接放在Tomcat里,浏览器在向Tomcat发requests时, Tomcat把jsp转化成java文件,再把java文件编译成class文件。没有用事先把jsp编译成class文件的那种发布方式。

 

    有三个文件,1. jsp 2. 生成的java文件  3. 生成的class文件。 有两个步骤,1. 把jsp转化成java文件, 2.把java文件编译成class文件.

注意Tomcat 5.5用Eclipse JDT Java Compiler来编译JSP文件,而不用JDK. 参见http://tomcat.apache.org/tomcat-5.5-doc/RELEASE-NOTES.txt

第一个问题,jsp的文件编码是什么?为什么这个问题对JSP编译成servlet有影响,探讨一下下面这个例子:

Java代码

<% String s = "哈"; %>  <h1><%=s%></h1> <% String s = "哈"; %><h1><%=s%></h1>

如果editor把jsp存成GBK文件编码,这个"哈"存在硬盘上的byte stream是两个byte, B9 FE,如果editor把jsp存成Uft-8文件编码,这个"哈"存在硬盘上的byte stream是三个byte,E5 93 88.(顺便提一下,“哈”的Unicode码是54 C8。)

这儿editor是起决定作用的,一定要搞清楚,editor存成文件用的编码是什么。对pageEncoding的设置一定要和存成的文件编码一至。 如果editor只能存成GBK,而pageEncoding错设置成UTF-8,这两个就不一至了。我见过很多人写XML文件时,错以为把最开头的 eccoding改成UTF-8就行了,结果editor不支持UTF-8,于是出错。

下一个步骤是Tomcate把jsp转化成java文件,Tomcate需要知道jsp文件的编码,要不碰上E5 93 88这三个byte,是把它们当 成UTF-8编成"哈"呢,还是把它们当成Latin-1(也就是ISO-8859-1)编成三个别的什么鬼符号呢? 根据Java  Server  Pages那本书的说法,jsp编译器先看pageEncoding,再看charset,如果两个都没有,那么如果jsp是用标准写法<% %>,就按ISO-8859-1,那么如果jsp是用XML语法写的,就按UTF-8. 生成的java文件的编码是什么,<TOMCAT_HOME>/conf/web.xml
里面有这么一句javaEncoding,Java file encoding to use for generating java source files. [UTF8] ,我校验了一下,是这样的. 由java编成class容易了,由UTF-8到UTF-8。生成的class文件用的肯定是UTF-8,jvm规范规定好的。

问题的关键在于Tomcat把Jsp转化成java文件是如何处理Jsp文件编码的,再往下研究就得看JSP2.0 的Specification和Tomcat的源代码。

原创粉丝点击