Java编码问题解决方案大揭密

本文为原创如需转载请注明作者和出处谢谢



一、Java编码是怎么回事

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

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

class 中国
{
    public String 雄起()
    {
         return "中国雄起";
    }
}

中国 祖国 = new 中国();
System.out.println(祖国.雄起());

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

class 수퍼맨
{
    public void スーパーマン() {  }
}

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

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

二、Java编码转换

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

    先定义一个字符串变量

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

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

System.out.println(gbk);

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

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

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

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

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

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

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

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

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

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

String s = "中";

MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[0].ToString());

MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[1].ToString());

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

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

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

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

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

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

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

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

String korean = "인간의"; // 共三个韩文字符我们只测试第一个“인”

System.out.println(Integer.toHexString(0xff & korean.getBytes("unicode")[2]));

System.out.println(Integer.toHexString(0xff & korean.getBytes("unicode")[3]));

System.out.println(Integer.toHexString(0xff & korean.getBytes("Cp949")[0]));

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.TXTJava支持的编码格式

三、属性文件

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

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

String name= ""u7528"u6237"u540d"u4e0d"u80fd"u4e3a"u7a7a"
;

System.out.println(name);

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

String ss = "用户名不能为空";
byte[] uncode = ss.getBytes("Unicode");
int x = 0xff;
String result ="";
for(int i= 2; i < uncode.length; i++)
{
    if(i % 2 == 0) result += "//u";
    String abc = Integer.toHexString(x & uncode[i]);            
    result += abc.format("%2s", abc).replaceAll(" ", "0");               
}
System.out.println(result);

 

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

/u7528/u6237/u540d/u4e0d/u80fd/u4e3a/u7a7a

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

四、Web中的编码问题

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

 

<!--  main.jsp  -->

  <%@ page language="java"  pageEncoding="utf-8"%>

  <html>
      <head>

      </head>

      <body>
          <form action="servlet/MyPost" method="post">
              <input type="text" name="user" />
              <p/>
              <input type="submit"  value="提交"/>
          </form>

      </body>
  </html>

    下面是个Servlet

  package servlet;

  import java.io.IOException;
  import java.io.PrintWriter;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;

  public class MyPost extends HttpServlet
  {

      public void doPost(HttpServletRequest request, HttpServletResponse response)
              throws ServletException, IOException
      {
          String user = request.getParameter("user");
          System.out.println(user);
      }
  }

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

    request.setCharacterEncoding("utf-8");

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

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

 

 

国内最棒的Google Android技术社区eoeandroid欢迎访问

《银河系列原创教程》发布

《Java Web开发速学宝典》出版欢迎定购

时间: 2024-11-30 21:14:06

Java编码问题解决方案大揭密的相关文章

java-求大神指教关于 Java 编码过程的详细描述。

问题描述 求大神指教关于 Java 编码过程的详细描述. 编码问题一直困扰我.以 Java 为例: 大家都知道 Java 的原始字符集是两字节的 Unicode,那么在写程序时,如果系统默认字符集是 GBK 那么在编译和解释该程序时,系统到底针对编码做了哪些事情,求大神指教. 解决方案 你用的汉字对应的是可以处理汉字的编码集的,比如GBK,你在网上搜一下,每个汉字在编码集中是以数字来代替这个字的,而当计算机处理时会将这个数字转换成 一串01到计算机中,当计算机接到这串01后它就知道了你这个数字是

Java前端Java编码语法运用

问题描述 Java前端Java编码语法运用 我刚入这行不久,小学生一枚,现在有个Java的问题如下:http://zhidao.baidu.com/question/1242054694549391659.html我挂在百度问答上了,会的大神们可以大体上先看一下,我的问题主要一个是:1.那个用js写的大致方法能否解决我的问题(我自己看了下,大致解决思路是没错的的)2.能解决的话能否帮我转成Java代码形式,用Java语法写个Demo?因为我对Java只是处于初级阶段,很多语法的使用和运用都不知道

java 调用wsdl接口 大神帮忙讲解一下

问题描述 java 调用wsdl接口 大神帮忙讲解一下 现有一接口是c++写的 java调用他如何调用这个接口?在浏览器上显示为 解决方案 参考下:http://yang-min.iteye.com/blog/600172

java菜鸟真心求教大神,谢谢!!!!

问题描述 java菜鸟真心求教大神,谢谢!!!! 我是大三学生,在学校有学些java的基础语言,想要深入学习java,请教大神分享心得 解决方案 这个帖子首先发错位置了,这里是技术区,你问的属于咨询类问题 java基础可以学习核心基础卷系列 然后有java编程思想 java深入虚拟机等 解决方案二: 数据库,网络,等等,够你学 解决方案三: 首先Java se基础,在学基础的时候会学到一些数据库,网络的基础知识,然后可以向这两个方面去深入发展 解决方案四: 如果基础不好,可以学一下<Java编程

java求哪位大神帮看看,分割可以,粘合不行!

问题描述 java求哪位大神帮看看,分割可以,粘合不行! import java.util.*;import java.io.*;class SplitDemo { public static void main(String[] args) throws IOException { //File file=new File(""D:我想念你.mp3""); File dir=new File(""D:splitfiles""

资料推荐--Google Java编码规范

之前已经推荐过Google的Java编码规范英文版了: http://google-styleguide.googlecode.com/svn/trunk/javaguide.html 虽然这篇文章的英文很简单,但是最近发现有人翻译了这篇文章,所以专门写一篇文章推荐一下: http://hawstein.com/posts/google-java-style.html   同时为了避免原始文章丢失,所以转了一下: 作者:Hawstein 出处:http://hawstein.com/posts/

关于java内存泄露求大神帮忙分析

问题描述 关于java内存泄露求大神帮忙分析 用MAT进行分析但是有点看不懂求大神帮忙分析一下 解决方案 Java内存泄露和分析Java内存泄露分析Java内存泄露问题分析 解决方案二: Details 看看 解决方案三: 你看看你有没有写入到内存里很大的文件 解决方案四: 这是今天重新定位问题的明细图片 解决方案五: 这是相关数据的图片

求大家帮帮小白吧-求在java这行业的大神帮我实现一个功能

问题描述 求在java这行业的大神帮我实现一个功能 一个会议室申请的页面功能,客户要填写会议开始时间与结束时间,然后选择会议室房间名称, 在这个时候,我该怎么去判断客户在这个申请时间与结束时间内有无其他客户在这个时间段有申请的记录,如果有,则在申请的客户不能申请这个时间段,和会议室房间名称,求大神给我一点帮助, 在此谢谢大家了,我纯属小白,在网上看了两个月视频教学,真心的没思路,现在还在努力学java相关的书籍视频教学.求大家帮帮忙. 解决方案 判断表中对应 的房间号在这段时间能有没有在用:sq

java web问题 求大神帮忙解答啊

问题描述 java web问题 求大神帮忙解答啊 如何实现你发表一个日志,让你自己和你的上级领导还有你的部门领导可以看到. 解决方案 如果你只是做一个学生习作,简单的做法是,你需要一个组织表 id userid superid,分别是当前用户id和上一级用户id 当某个用户看日志的时候,先通过递归上面的表,找到所有的自己下属的id,然后作为条件查询他们发的日志. 解决方案二: 设置权限啊 解决方案三: 日志信息入库,如果领导用户登录,就查询日志显示. 解决方案四: 根据登陆的ID设置展示权限