前几天在使用中兴的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中编码的问题,也算是一个抛砖引玉的过程,欢迎指正。