java编码问题(中文乱码的原因)

来源:互联网 发布:mysql 最近一条记录 编辑:程序博客网 时间:2024/03/29 23:23

现象

      前段时间有个需求:应用appA将商品快照保存在本地日志文件itemSnap.log中,中间插件负责将日志文件的内容放到队列里,应用appB再获取队列中的内容后持久化到HBase。在HBase里的中文出现乱码。


原因

       整个过程可简化为:appA编码方式:  String.getBytes(); appB的解码方式:  new String(byte[] bytes, "UTF-8")。可以看出,appA没有显示指明编码方式,此时会采用系统默认编码,当解码过程采用的字符集跟编码过程采用的字符集不匹配时,就会出现乱码问题。这也是为什么出现appA部署有的机器上不会有中文乱码,而有的机上有乱码问题。解决方案:改用String.getBytes(“UTF-8”)


总结:

编码过程的实质是:字符变为字节数据。 数据存储在内存或磁盘,或在网络之间传输都是以字节的形式存在。

解码的过程实质是:字节数据变为字符。 

乱码问题产生的原因:解码和编码过程采用了不匹配的字符集。


下面这个例子展示了,同一段字符,采用不同的字符集得到的字符数组不同

import java.io.UnsupportedEncodingException;import java.util.Arrays;/** *  * 类Encoding.java的实现描述: * 编码:字符 --> 字节数组 *     String.getBytes(); *     String.getBytes(Charset charset) * 解码: 字节数组 --> 字符  *     new String(byte[] bytes); *     new String(byte[] bytes, Charset charset)   * 几种不同的编码格式 * UTF-8:变长。单字节范围内的字符使用一个字节表示,汉字采用3个字节。与GBK和GB231不同,无需查码表。编码效率更高。该编码适合网络船和,是理想的中文编码 * UTF-16:定长。对单字节范围内的高位补0变成两字节,不同处理器对2字节处理方式不同,big-endian和little-endian。 *            浪费了存储空间。适合在本地磁盘和内存之间使用,是java的内存编码。 * GBK:跟GBK2312采用相同的编码算法,包含更多的汉字字符。 * GBK2312:该字符集有一个char到byte的码表,不同的字符编码就查这个码表找到与每个字符的对应的字节,然后拼装成byte数组 * ISO-8859-1:单字节编码,中文字符经过这种编码会丢失信息。是大部分基础的java框架或系统默认的字符编码 * @author cici 2013-12-9 下午9:02:18 */public class Encoding {        public static void main(String[] args) {String string = "你好cc";try {    byte[] gbkByteArr = string.getBytes("GBK");      System.out.println(Arrays.toString(gbkByteArr));        byte[] utf8ByteArr = string.getBytes("UTF-8");    System.out.println(Arrays.toString(utf8ByteArr));        byte[] utf16ByteArr = string.getBytes("UTF-16");    System.out.println(Arrays.toString(utf16ByteArr));        byte[] isoByteArr = string.getBytes("ISO-8859-1");    System.out.println(Arrays.toString(isoByteArr));        } catch (UnsupportedEncodingException e) {    e.printStackTrace();}    }}

乱码问题现象补充

 1.       查看服务器上的日志文件,利用vim abc.log打开,中文乱码,而利用more abc.log显示正常。这是因为vim 和more工具首先从内存中读取文件内容,再对文件内容进行解码(字节数组变为字符)。

        解决方案:  在vim打开文件后,利用set enc=utf-8命令来临时设置字符集。不强制指定字符集会采用系统默认编码。 查看系统默认编码命令echo $LANG。

2.      web应用提供了文件上传功能,当上传文件中有中文时, 在开发机测试时,中文无乱码;而在daily环境中文乱码。这是因为采用

BufferedReader in= new BufferedReader(new InputStreamReader(inputStream));

会使用系统默认编码,InputStreamReader提供两种方式: InputStreamReader(InputStream in, Charset cs),InputStreamReader(InputStream in, String charsetName) 显示指定编码方式
   

0 0
原创粉丝点击