中文编码笔记

阅读更多
问题描述:

上周在压缩tar格式文件的时候, 遇到了乱码问题。
既是文件名在tar文件中显示为乱码。 如下图所示

中文编码笔记_第1张图片

你好被转换成了 浣犲ソ

为什么会这样, 首先要了解一下中文编码。

国标码和unicode
国家标准强制标准冠以“GB”。现时中华人民共和国官方强制使用GB 18030标准,但较旧的计算机仍然使用GB 2312。
正如chrome浏览器里面所显示的三种中文编码-> utf-8, gbk, gb18030.
个人感觉一般开发都使用utf8和gbk编码。
而 "你好"->"浣犲ソ" 在这里也正是使用gbk标准来解码utf8编码文字所产生的错误。


GBK和Unicode的编码表
utf8: http://blog.csdn.net/qiaqia609/article/details/8069678
gbk: http://ff.163.com/newflyff/gbk-list/

这里就查看“你”这个汉字是怎么编码的。 在GBK中。对应的是C4 E3,而在utf-8中,对应的是E4 BD A0。
(注:最初我以为gbk的编码和utf8的编码之间会有一定的联系,一直在找它们的规律。结果发现, 我完全想错了。 他们的编码是没有什么可以转换的关系的。后面再说)

编码解码过程
上述编码全部都是十六进制的数字。 这里说一下编码解码的过程,拿
String str="你" 为例,先看一下文字是如何转换为二进制的。
GBK:
String gbk="你";
		
		byte[] bytes=gbk.getBytes("gbk");
		
		System.out.println(bytes.length);
		
		for(int i=0;i 
 
这里的重点是方法 getBytes(Charset charset)。
该方法说明如下:
Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.
所以byte[] bytes=gbk.getBytes("gbk")就将“你”这个汉字根据gbk编码标准,转换成了二进制的byte对象,放入byte[] bytes中。

后面的Integer.toHexString(code).toUpperCase()就会输出两个二进制字节所对应的十六位数字, 也就是C4 E3, 既GBK编码标准表中的“你”的区域位置。


那么软件又是如何解码的呢?
假如在上面的代码后面加入:
String gbk2=new String(bytes);
		System.out.println(gbk2);

运行程序,就会看到这里输出的是 ��。
原因就是,程序在编码的时候用的是gbk标准,产生了16位长度的二进制数字。
而我们的class文件的格式是utf-8的, 当使用new String(bytes)时,程序会 默认使用utf8标准来进行解码。 这样自然不能正确的解码gbk格式的二进制数字。

就好比我们用realplayer去播放mkv格式的视频,是无法播放的, 因为realplayer不知道如何去解码mkv格式。

解决办法很简单,查看String的构造函数,就能看到
java.lang.String.String(byte[] bytes, String charsetName) throws UnsupportedEncodingException

Constructs a new String by decoding the specified array of bytes using the specified charset. The length of the new String is a function of the charset, and hence may not be equal to the length of the byte array.


通过使用特定编码来解码bytes数组来创建一个String对象。
因此只要使用
String gbk2=new String(bytes,"gbk");
		System.out.println(gbk2);

运行程序,就能看到正确的“你”的显示了。
因为程序调用了GBK标准,并以正确的解码方法,既两个字节表示一个汉字,来查找GBK标准表中所对应的汉字,就找到了“你”。


系统默认编码
我们的系统默认是使用unicode标准对文件进行编码解码的。
以win7为例, 打开控制面板->区域和语言-》管理, 可以看到:

中文编码笔记_第2张图片
所谓非Unicode程序所使用的语言, 既是当我们打开一个程序,而该程序所使用的编码不是Unicode, 这时候系统要使用的解码方法。

举个例子, 我们要打开一个日文软件,该日文软件并不是使用的utf8编码,而是其它的日本本地的编码, 这时候系统便会调用我们在这里所设置的 非Unicode程序所使用的语言。 我猜大概就是GBK GB之类的。 于是我们就能看到满屏的乱码。
因此我们如果把这里修改为 日本(日语),重启电脑再打开该日文软件,就会正确显示日文了。 原因也就是系统用正确的编码标准来解码了。



tar文件名乱码问题
回到最初遇到的问题。我在网上查了很久, 最后看到
http://www.dewen.org/q/4494/ 这里说 tar压缩格式不会记录字符集, 而rar和zip会。   如果这样的话, 那tar真是不适合中文。

具体来说就是, 文件名被压缩程序设置了utf8编码, 但是到了tar中, tar不支持utf8,于是我们的系统就使用了 非Unicode程序所使用的语言来进行解码。
于是呢, 就有了以下步骤:


1. 定义了一个字符“你”, 然后该字符被用'utf8'编码, 变成了2进制11100100,10111101,10100000
之后此二进制被传入了某一个程序中, 该程序不知道‘你’这个字是什么编码格式的, 于是尝试用gbk进行解码。
GBK是怎么解码的呢? 会把这段二进制当做每16位表示一个字符。
于是前面的11100100,10111101就被提取了出来, 然后程序开始在GBK编码表中搜索对应的字符。
结果就找到了 E4 BD->浣 。
接下来的10100000没法解码, 就出来了一个问号'?'。


这段话是之前做的笔记, 也就是系统使用国标码标准来解码utf-8编码文字所出现的问题。




最后放上tar文件压缩的问题代码。


System.out.println(System.getProperty("file.encoding"));
		System.out.println(Charset.defaultCharset().name());
		
		
		String path="D:\\_thumbnail";
		String f="d:\\t.tar";
		TarArchiveOutputStream taos=new TarArchiveOutputStream(new FileOutputStream(f),"utf-8");//这里设置为GBK就可以解决乱码问题
		
		
		
		File of=new File(path);
		
		File[] ofs=of.listFiles();
		System.out.println(ofs.toString());
		for(File off:ofs){
			String parent=off.getParentFile().getParent(); //D:/
			String parent_relative=off.getParentFile().getAbsolutePath().substring(parent.length());
			
			FileInputStream fis=new FileInputStream(off);
			System.out.println(File.separator);
			TarArchiveEntry tae=new TarArchiveEntry(parent_relative+File.separator+new String(off.getName().getBytes("utf-8")));//这里的参数是压缩文件里的路径,也就是文件夹和文件名
															//比如_thumbnail/1.jpg,就会产生一个_thumnbnail的文件夹和一个1.jpg的文件。
			tae.setSize(off.length());
			taos.putArchiveEntry(tae);
			
			IOUtils.copy(fis, taos);
			fis.close();
			taos.closeArchiveEntry();
		}



TarArchiveOutputStream taos=new TarArchiveOutputStream(new FileOutputStream(f),"utf-8");//这里设置为GBK就可以解决乱码问题

Constructor for TarInputStream.

Parameters:
os the output stream to use
encoding name of the encoding to use for file names



如注释写的一样, 这里不写编码格式,则会使用默认的utf-8来进行文件名编码。
之所以设置GBK编码不会出现乱码,就是因为系统得不到tar压缩文件名的编码信息,就采用了非Unicode所使用语言,既GBK, 来进行解码。


解决方法:
压缩tar文件时,文件名用英文即可。

终于写完了-O- 写的不是一般的乱

  • 中文编码笔记_第3张图片
  • 大小: 23.6 KB
  • 中文编码笔记_第4张图片
  • 大小: 47.2 KB
  • 查看图片附件

你可能感兴趣的:(编码,utf-8,unicode,gbk)