`

Java编码原理与解决方案 .

 
阅读更多

一、Java编码是怎么回事?

对于使用中文以及其他非拉丁语系语言的开发人员来说,经常会遇到字符集编码问题。对于Java语言来说,在其内部使用的是UCS2编码(2个字节的Unicode编码)。这种编码并不属于某个语系的语言编码,它实际上是一种编码格式的世界语。在这个世界上所有可以在计算机中使用的语言都有对应的UCS2编码

正是因为Java采用了UCS2,因此,在Java中可以使用世界上任何国家的语言来为变量名、方法名、类起名,如下面代码如下:

 

01 class 中国
02 {
03     public String 雄起()
04     {
05          return "中国雄起";
06     }
07 }
08  
09 中国 祖国 = new 中国();
10 System.out.println(祖国.雄起());



 

    哈哈,是不是有点象“中文编程”。实际上,也可以使用其他的语言来编程,如下面用韩文和日文来定义个类:

 

 

1 class {
2     public void スーパーマン() {  }
3 }

    实际上,由于Java内部使用的是UCS2编码格式,因为,Java并不关心所使用的是哪种语言,而只要这种语言在UCS2中有定义就可以。

    UCS2编码中为不同国家的语言进行了分页,这个分页也叫“代码页”或“编码页”。中文根据包含中文字符的多少,分了很多代码页,如cp935cp936等,然而,这些都是在UCS2中的代码页名,而对于操作系统来说,如微软的windows,一开始的中文编码为GB2312,后来扩展成了GBK。其实GBKcp936是完全等效的,用它们哪个都行。

二、Java编码转换

    
上面说了这么多,在这一部分我们做一些编码转换,看看会发生什么事情。

    先定义一个字符串变量:

1 String gbk = "中国"// “中国”在Java内部是以UCS2格式保存的

    用下面的语言输出一定会输出中文:

1 System.out.println(gbk);

    实现上,当我们从IDE输入“中国”时,用的是java源代码文件保存的格式,一般是GBK,有时也可是utf-8,而在Java编译程序时,会不由分说地将所有的编码格式转换成utf-8编码,读者可以用UltraEdit或其他的二进制编辑器打开上面的“中国.class”,看看所生成的二进制是否有utf-8的编码(utf-8ucs2之间的转换非常容易,因为utf-8ucs2之间是用公式进行转换的,而不是到代码页去查,这就相当于将二进制转成16进制一样,4个字节一组)。如“中国”的utf-8编码按着GBK解析就是“涓  浗”。如下图所示。

diyblPic

如果使用下面的语言可以获得“中国”的utf-8字节,结果是6(一个汉字由3个字节组成)

1 System.out.println(gbk.getBytes("utf-8").length);

下面的代码将输出“涓  浗”。

1 System.out.println(new String(gbk.getBytes("utf-8"), "gbk"));

 

由于将“中国“的utf-8编码格式按着gbk解析,所以会出现乱码。

如果要返回中文的UCS2编码,可以使用下面的代码:

1 System.out.println(gbk.getBytes("unicode")[2]);
2  
3 System.out.println(gbk.getBytes("unicode")[3]);

 

 

前两个字节是标识位,要从第3个字节开始。还有就是其他的语言使用的编码的字节顺序可能不同,如在C#中可以使用下面的代码获得“中国“的UCS2编码:

1 String s = "中";
2  
3 MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[0].ToString());
4  
5 MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[1].ToString());

 

 

    使用上面的java代码获得的“中“的16进制UCS2编码为4E2D,而使用C#获得的相应的ucs2编码为2D4E,这只是C#Java编码内部使用的问题,并没有什么关系。但在C#Java互操作时要注意这一点。

    如果使用下面的java编码将获得16进制的“中”的GBK编码:

 

1 System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[0]));
2  
3 System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[1]));

 

 

“中”的ucs2编码为2D4EGBK编码为D6D0

    读者可访问如下的url自行查验:

    http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT

    当然,感兴趣的读者也可以试试其他语言的编码,如“人类”的韩语是“???”,如下面的代码将输出“???”的cp949ucs2编码,其中cp949是韩语的代码页。



 

1 String korean = "???"// 共三个韩文字符,我们只测试第一个“?”
2  
3 System.out.println(Integer.toHexString(0xff & korean.getBytes("unicode")[2]));
4  
5 System.out.println(Integer.toHexString(0xff & korean.getBytes("unicode")[3]));
6  
7 System.out.println(Integer.toHexString(0xff & korean.getBytes("Cp949")[0]));
8  
9 System.out.println(Integer.toHexString(0xff & korean.getBytes("Cp949")[1]));

上面代码的输出结果如下:

c7

78

c0

ce

    也就是说“?”的ucs2编码为C778cp949的编码为C0CE,要注意的是,在cp949中,ucs2编码也有C0CE,不要弄混了。读者可以访问下面的url来验证:

http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT

http://www.bt285.cn/content.php?id=1196863

Java支持的编码格式

三、属性文件

Java中的属性文件只支持iso-8859-1编码格式,因此,要想在属性文件中保存中文,就必须使用UCS2编码格式("uxxxx),因此,出现了很多将这种编码转换成可视编码和工具,如Eclipse中的一些属性文件编辑插件。

实际上,"uxxxx编码格式在javaC#中都可以使用,如下面的语句所示:

1 String name= ""u7528"u6237"u540d"u4e0d"u80fd"u4e3a"u7a7a" ;
2  
3 System.out.println(name);

 

    上面代码将输出“用户名不能为空”的信息。将"uxxxx格式显示成中文非常简单,那么如何将中文还原成"uxxxxx格式呢?下面的代码完成了这个工作:


01 String ss = "用户名不能为空";
02 byte[] uncode = ss.getBytes("Unicode");
03 int x = 0xff;
04 String result ="";
05 for(int i= 2; i < uncode.length; i++)
06 {
07     if(i % 2 == 0) result += "\\u";
08     String abc = Integer.toHexString(x & uncode[i]);           
09     result += abc.format("%2s", abc).replaceAll(" ""0");              
10 }
11 System.out.println(result);

 

 

    上面的代码将输出如下结果:


\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a

    好了,现在可以利用这个技术来实现一个属性文件编辑器了。

四、Web中的编码问题

    大家碰到最多的编码问题就是在Web应用中。先让我们看看下面的程序:

 

01 <!--  main.jsp  -->
02  
03   <%@ page language="java"  pageEncoding="utf-8"%>
04  
05   <html>
06       <head>
07  
08       </head>
09  
10       <body>
11           <form action="servlet/MyPost" method="post">
12               <input type="text" name="user" />
13               <p/>
14               <input type="submit"  value="提交"/>
15           </form>
16  
17       </body>
18   </html>


 


    下面是个Servlet


  

01 package servlet;
02  
03   import java.io.IOException;
04   import java.io.PrintWriter;
05   import javax.servlet.ServletException;
06   import javax.servlet.http.HttpServlet;
07   import javax.servlet.http.HttpServletRequest;
08   import javax.servlet.http.HttpServletResponse;
09  
10   public class MyPost extends HttpServlet
11   {
12  
13       public void doPost(HttpServletRequest request, HttpServletResponse response)
14               throws ServletException, IOException
15       {
16           String user = request.getParameter("user");
17           System.out.println(user);
18       }
19   }

 

 

    如果中main.jsp中输入中文后,向MyPost提交,在控制台中会输出“????”,一看就是乱码。如果将IE的当前编码设成其他的,如由utf-8改为gbk,仍然会出现乱码,只是乱得不一样而已。这是因为客户端提交数据时是根据浏览器当前的编码格式来提交的,如浏览器当前为gbk编码,就以gbk编码格式来提交。 这本身是不会出现乱码的,问题就出在Web服务器接收数据的时候,HttpServletRequest在将客户端传来的数据转成ucs2上出了问题。在默认情况下,是按着iso-8859-1编码格式来转的,而这种编码格式并不支持中文,所以也就无法正常显示中文了,解决这个问题的方法是用和客户端浏览器当前编码格式一致的编码来转换,如果是utf-8,则在doPost方法中应该用以下的语句来处理:

1 request.setCharacterEncoding("utf-8");

    为了对每一个Servlet都起作用,可以将上面的语句加到filter里。

    另外,我们一般使用象MyEclipse一样的IDE来编写jsp文件,这样的工具会根据pageEncoding属性将jsp文件保存成相应的编码格式,但如果要使用象记事本一样的简单的编辑器来编写jsp文件,如果pageEncodingutf-8,而在默认时,记事本会将文件保存成iso-8859-1ascii)格式,但在myeclipse里,如果文件中有中文,它是不允许我们保存成不支持中文的编码格式的,但记事本并不认识jsp,因此,这时在ie中就无法正确显示出中文了。除非用记事本将其保存在utf-8格式。如下图:

分享到:
评论

相关推荐

    Java Web开发中的中文乱码问题分析及解决方案.pdf

    在进行java Web开发的过程中,由于采用的编码和解码的方式不统一,...文中首先介绍了java Web的编码机制及JSP运行原理,继而阐述了在开发过程中常见的乱码问题及解决方案,最后提出采用过滤器重写getParameter方法,实现...

    java中文问题.pdf

    java中文编码的原理到解决方案

    Java 面试宝典

    一. Java 基础部分............................................................................................................43、Java 中的异常处理机制的简单原理和应用。 .....................................

    基于Java的猜拳小游戏设计.doc

    目 录 绪论 - 1- 一、背景与意义 - 2- 二、设计原理与方案 - 2- 一)方案 - 2- 二)设计思路 - 3- 三)系统分析 - 3- 四)程序概要设计 - 4- 五)工作流程图 - 4- 六)程序框图 - 5- 七)程序中所用类说明 - 5- 八)...

    做Java项目过程中遇到乱码问题的解决方案

    我花了一些时间自己动手实验了一把,虽然没有洞悉编码,解码这些底层原理,但是解决实际问题应该足够了。这里主要针对java web项目中的文乱码问题。  从浏览器采用form方式提交数据到服务器,可以分为post和get...

    Eclipse权威开发指南2.pdf

    第4章 Java程序的运行与调试 107 4.1 运行Java代码...... 108 4.1.1 使用运行和调试命令..... 108 4.1.2 管理启动配置..... 109 4.1.3 对代码片断编辑测试窗页面中的表达式进行求值..... 111 4.2 调试...... 112 ...

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

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    一篇不错的关于java工作流方面讲解及代码

    2.3.1 JSP的运行原理 7 2.3.2 JSP的生命周期 8 2.3.3 Servlet和JavaBean技术介绍 8 2.3.4 Java 虚拟机 9 2.3.5 JSP访问SQL Server 2000数据库 9 2.4 数据库后台环境配置 10 2.5 系统开发工具简介 10 2.5.1 ...

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

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java面试题

    并发问题解决方案 59 71.7. Hibernate是如何延迟加载? 60 71.8. Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系) 60 71.9. 说下Hibernate的缓存机制 60 71.10. Hibernate的查询方式 60 71.11. 如何...

    Java架构面试专题汇总

    软件架构指的是软件的顶层结构,而架构设计是为了应对软件系统的复杂度而提出的解决方案,并不是所有的项目都需要架构,在错误的地方去做架构只会本末倒置 然后说java架构师,那就是在java领域内解决这个问题的人员...

    Eclipse权威开发指南3.pdf

    第4章 Java程序的运行与调试 107 4.1 运行Java代码...... 108 4.1.1 使用运行和调试命令..... 108 4.1.2 管理启动配置..... 109 4.1.3 对代码片断编辑测试窗页面中的表达式进行求值..... 111 4.2 调试.....

    Eclipse权威开发指南1.pdf

    第4章 Java程序的运行与调试 107 4.1 运行Java代码...... 108 4.1.1 使用运行和调试命令..... 108 4.1.2 管理启动配置..... 109 4.1.3 对代码片断编辑测试窗页面中的表达式进行求值..... 111 4.2 调试.....

    Java并发编程培训(阿里巴巴).ppt

    阿里巴巴内部培训资料,结合案例详细讲述了java并发编码的工作原理和解决方案。

    webx3框架指南PDF教程附学习Demo

    现在有很多Java的Web框架可供选择,并且它们也都是免费的。例如: • Struts • Webwork • Tapestry • Spring MVC 以上框架都是非常优秀的。说实话,如果阿里巴巴网站在2001年开始,就有这么多可选择的话,...

    java实现工作流

    2.3.1 JSP的运行原理 7 2.3.2 JSP的生命周期 8 2.3.3 Servlet和JavaBean技术介绍 8 2.3.4 Java 虚拟机 9 2.3.5 JSP访问SQL Server 2000数据库 9 2.4 数据库后台环境配置 10 2.5 系统开发工具简介 10 2.5.1 ...

    基于JAVA的RSA文件加密软件的设计与实现(源代码+论文).rar

    本源码文件包名为“基于JAVA的RSA文件加密软件的设计与实现”,是一个针对毕业设计或课程设计的完整项目解决方案。它主要实现了使用Java语言开发的RSA算法进行文件加密的功能,旨在帮助学生深入理解公钥加密技术,并...

Global site tag (gtag.js) - Google Analytics