Java中关于乱码的认识和解决办法

前几天在使用中兴的MM7接口开发一个彩信的应用,但是在测试的时候,手机收到的文本内容老是一堆乱码,无论怎么修改参数问题都得不到解决,因而就狠狠的琢磨和研究了下关于编码的内容,最终成功解决了乱码的问题。java


咱们都知道Java语言使用的是Unicode编码。但是你们是否真的已经理解了这句话的含义? Unicode编码和咱们经常使用的UTF-8,GBK有什么关系呢? 那接下来就来讨论下这个话题。数据库


不知你们还有没想过,咱们在Java代码里面定义一个字符串字面量的时候,该字符串在JVM中的编码是什么?  是的,上面也说了Java语言用的是Unicode编码,因此这样定义的字符串字面量天然就是Unicode编码表示的。 然而除了这种程序内部的数据外,咱们常常还会从外部获取各类各样的数据让程序处理,例如经过IO从硬盘上读取文件,经过JDBC查询数据库等,而这些数据的编码格式是多种多样的,例若有的多是UTF-8,有的多是GBK等,那么这样的一些数据在JVM中又是以什么编码表示的呢?数组


上面提到了几个问题,如今返回去简单的说说编码,固然这里只是粗略的说起,毕竟网上这方面的内容不少。ide


咱们首先要弄清楚两个概念,“字符集编码”和“编码格式”。所谓“字符集编码”就是由某个组织制定的一张“字符与编号的映射关系表”,例如: 10001 == “我”, 10002 = “们”。 咱们所谓的Unicode字符集就是这样的一张关系表。测试


而UTF-8是一种实现了Unicode字符集中部分字符编码的“编码格式”,它存在目的是为了保存或者传输数据用的。那么既然在字符集中已经有了映射关系了,为何还要再来编码。缘由好几个,例如考虑文件大小的问题,使用效率的问题,和其余字符集区分的问题等。编码


那么UTF-8编码又是对Unicode字符集中的哪部分编码呢? 就是“字符编号”,例如上面的10001,10002.  而对于UTF-8的编码规则能够网上查阅.操作系统


那如今咱们就应该清楚了,在JVM中表示字符串“咱们”使用的编码为“1000110002”这样的格式,也就是使用的是Unicode的编号。那当咱们经过IO将一个以UTF-8编码的文本文件读入内存的时候,极可能咱们会使用到这样的代码:code


new InputStreamReader(new FileInputStream(file),"UTF-8")对象


这里指定的“UTF-8”就是文件的编码格式,它的目的是告诉负责解码的对象要按照“UTF-8”的编码格式来解码成JVM使用的Unicode编码。那若是咱们这里指定为“GBK”的话,咱们所获得的可就是一堆乱码啦。接口


若是String content = (文件内容) 。 那么这个content在这个时候已是Unicode编码了。不知道如今为止是否应该明白了些什么。


若是你看到这样的代码:
String msg  = "我是一个字符串" ;
String res = new String(msg.getBytes("utf-8"),"GBK") ;

那这里的res打印出来也就是一堆乱码了。这里的操做过程实际上是:
1,将Unicode编码的msg按照UTF-8的编码格式进行编码,从而获得UTF-8编码的字节数组。
2,将字节数组按照GBK的编码格式来解码成Unicode编码的字符
3,惋惜UTF-8和GBK不兼容,他们使用了不一样的编码集,因此乱码出来啦


在进行http请求的时候,咱们须要告诉对方咱们发送的数据的编码格式是什么,若是对方按照咱们的告知的编码格式来解码,而咱们却把错误的编码格式告诉了对方,那么接下来的事情就是对方收到了一堆的乱码。


还有就是咱们在进行这样的操做的时候:"我是一个字符串".getBytes(); 可要当心了,这个时候获得的字节数组但是你操做系统默认的编码格式(固然咱们还能够在启动的时候指定咱们默认的编码格式)。


下面再追加点编码解码的例子,供你们理会:

//定义一个Unicode字符类型的字符串
  String msg = "我是一个字符串哦,仍是Unicode编码的。體發財"  ;
  System.out.println("原有字符串:"+msg);
  System.out.println("=============");
  //将Unicode编码按照GBK编码格式进行编码
  byte[] gbkbyts = msg.getBytes("GBK");
  
  /*
   * 原本是GBK编码的字节,咱们使用UTF-8来解码.固然此时必然会是乱码。
   * 
   * 注意:若是在第一次解码的时候使用这种错误的解码方式,
   * 那么后面将没法再恢复,下面的例子能够看到。
   * */
  String utf8Str = new String(gbkbyts,"UTF-8") ;
  System.out.println("UTF-8解码后的字符串:"+utf8Str);
  /*
   * 接下来咱们把该字符串按照UTF-8的编码格式再编码回去.
   * 但这个时候gbkbyts和utf8Byts已经彻底不一样了。
   * */
  byte[] utf8Byts = utf8Str.getBytes("UTF-8") ;
  /*
   * 接着咱们再来按照GBK的编码格式来解码.
   * 获得的天然是乱码。
   * */
  String utf2GbkStr = new String(utf8Byts,"GBK") ;
  System.out.println("GBK解码UTF-8编码后的字符串:"+utf2GbkStr);
  System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
  /*
   * 可是,若是咱们第一次解码的时候使用的是单字节的编码格式来解码,那后面是能够再恢复的。
   * 但是还有一个要求,就是要保证该单字节的编码会利用上全部的8位,
   * 也就是说能够表示256个字符的才行。
   * 
   * 
   *单字节的编码格式有两种, ASCII和ISO-8859-?
   *ASCII使用了7位来表示字符,最高位永远为0,其能够表示的范围只有128个字符。
   *ISO-8859-?(问号表示1,2,3…11,13…16,没有12,表示15个字符集)
   *使用8位来表示字符,总共能够表示256个字符。
   *
   *这两种单字节编码,咱们最经常使用的也就是ISO-8859-1
   * */
  //转换为ASCII码的字符串
  String ascStr = new String(gbkbyts,"ASCII") ;
  System.out.println("ASCII解码后的字符串:"+ascStr);
  //再将ASCII转换为GBK
  String gbkStr = new String(ascStr.getBytes("ASCII"),"GBK") ;
  System.out.println("将ASCII编码按照GBK编码格式解码:"+gbkStr);
  System.out.println("===============================");
  
  
  String isoStr = new String(gbkbyts,"ISO-8859-1") ;
  System.out.println("ISO-8859-1解码后的字符串:"+ascStr);
  //再将ASCII转换为GBK
  String gbkStr1 = new String(isoStr.getBytes("ISO-8859-1"),"GBK") ;
  System.out.println("将ISO-8859-1编码按照GBK编码格式解码:"+gbkStr1);

其运行结果以下:

原有字符串:我是一个字符串哦,仍是Unicode编码的。體發財
=============
UTF-8解码后的字符串:???????????????????Unicode???????w?l?
GBK解码UTF-8编码后的字符串:锟斤拷锟斤拷一锟斤拷锟街凤拷锟斤拷哦锟斤拷锟斤拷锟斤拷Unicode锟斤拷锟斤拷摹锟斤拷w锟絣財
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASCII解码后的字符串:??????????????????????Unicode?????????w?l??
将ASCII编码按照GBK编码格式解码:??????????????????????Unicode?????????w?l??
===============================
ISO-8859-1解码后的字符串:??????????????????????Unicode?????????w?l??
将ISO-8859-1编码按照GBK编码格式解码:我是一个字符串哦,仍是Unicode编码的。體發財


以上的内容大概的讲了下关于java中编码的问题,也算是一个抛砖引玉的过程,欢迎指正。

相关文章
相关标签/搜索