您的位置:首页 > 编程语言 > Java开发

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

2013-12-15 22:02 281 查看
现象

前段时间有个需求:应用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) 显示指定编码方式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐