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

现象

      前段时间有个需求:应用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) 显示指定编码方式
   

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值