`

中文编码笔记

阅读更多
问题描述:

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



你好被转换成了浣犲ソ

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

国标码和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<bytes.length;i++){
			System.out.println(bytes[i]);
			int code= bytes[i]+256;
			System.out.println(code);//C4 E3
		}

这里的重点是方法 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为例, 打开控制面板->区域和语言-》管理, 可以看到:


所谓非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- 写的不是一般的乱

  • 大小: 23.6 KB
  • 大小: 47.2 KB
分享到:
评论

相关推荐

    JavaFX+Jfoenix 学习笔记(十)--系统托盘及解决中文乱码问题源码

    在本篇JavaFX+Jfoenix学习笔记中,我们将探讨如何在JavaFX应用程序中实现系统托盘功能,以及如何解决可能出现的中文乱码问题。系统托盘是现代桌面应用中常见的一种特性,允许用户在关闭主窗口后,仍然可以通过托盘...

    stm32笔记:解决mdk编辑代码时的各种乱码问题

    STM32笔记:解决MDK编辑代码时的乱码问题 在进行STM32嵌入式开发时,我们经常会使用Keil uVision(MDK)作为集成开发环境(IDE)。然而,由于各种原因,比如文件编码不一致或者IDE设置不当,可能会导致在MDK中编辑...

    JavaWeb开发中文乱码问题解决方案

    在JavaWeb开发中,中文乱码问题是一个...总之,解决JavaWeb开发中的中文乱码问题,关键在于理解和掌握字符编码,以及熟练使用过滤器技术。通过以上方法,开发者可以有效地防止和解决乱码问题,提高应用程序的用户体验。

    MLX90640开发笔记(完整十章20191012).pdf

    本文件是MLX90640的产品开发笔记,包含了基本资料下载、中文资料、驱动移植、操作流程、计算方法、注意事项、插值处理、伪彩编码。 共分为十章 MLX90640开发笔记(一)概述及开发资料准备 MLX90640开发笔记(二)API...

    12864显示汉字开发笔记及程序

    3. **汉字编码**:在12864 LCD上显示汉字,需要了解汉字的编码方式,如GB2312或GBK编码。每个汉字对应一个特定的二进制码,这个码会被转换为点阵数据用于显示。 4. **点阵字体生成**:汉字由点阵组成,需要将汉字...

    字符编码笔记:ASCII,Unicode和UTF-8

    它是一种通用字符集,旨在为世界上的每一种语言提供唯一的字符编码,从而避免了编码不一致带来的乱码问题。Unicode目前可以支持超过一百万个不同的符号。 - **符号定义**:每个符号都有一个唯一的Unicode编码。例如...

    字符编码笔记:ASCII-Unicode和UTF-8

    字符编码笔记:ASCII、Unicode 和 UTF-8 本文主要介绍了字符编码的基本概念和历史发展过程,包括 ASCII 码、Unicode 和 UTF-8 的编码原理和特点。文章首先介绍了 ASCII 码的历史和编码原理,然后讨论了非 ASCII ...

    字符编码笔记:ASCII,Unicode和UTF-8[参照].pdf

    字符编码笔记:ASCII, Unicode 和 UTF-8 本篇笔记主要介绍了字符编码的基础知识,包括 ASCII 码、Unicode 和 UTF-8 等概念。文章首先介绍了 ASCII 码的历史和原理,接着讨论了 Unicode 的提出和发展,最后解释了 ...

    usb3.0 协议全文及中文笔记

    《USB 3.0协议中文版笔记.doc》可能包含了对协议的详细解读,包括USB 3.0的架构、协议栈、物理层和链路层的详细说明,以及关于设备枚举、数据传输、电源管理等关键概念的解释。而《usb_30_spec_032310》很可能是英文...

    mysql中文详细笔记.zip

    掌握了这些编码知识,用户就可以在存储和检索数据时,有效地避免乱码问题。 “MySQL.txt”文件是整个压缩包的精华所在,它提供了文字版的详细笔记。这些笔记不仅包含了概念性的解释,还包括大量的实例代码和实践...

    Java学习笔记

    5、如何处理中文乱码问题 6、使用JavaMail发送注册验证邮件 7、不安全的用户名密码验证 8、用Session保存登录信息 9、面向对象分析通常分为三个步骤 10、使用DataSource接口连接数据源 11、避免表单重复提交的技术 ...

    ExtJS4中文教程2 开发笔记 chm

    Javascript 汉字编码转换 Javascript 面向对象之封装 Javascript 面向对象之构造函数的继承 Javascript 面向对象之非构造函数的继承 JavaScript对象与继承教程之内置对象(下) JavaScript对象及继承教程(上) ...

    JAVAWeb全课程笔记( html版)

    [总结]JavaWeb乱码问题 [转自IBM]中文编码问题 JDBC入门 Jdbc事务控制管理 常用数据库连接池 编写JDBC框架 客户信息管理系统 Servlet Filter 过滤器 HTTP 协议 文件上传和下载 Servlet事件监听器 JavaMail开发 ...

    Eclipse开发学习笔记.pdf

    ### Eclipse开发学习笔记知识点解析 #### 一、Eclipse工作台(Workbench) Eclipse工作台是Eclipse提供的集成开发环境的核心部分,旨在为开发者创建一个无缝集成的工具集,以便于管理和导航工作空间资源。它是开发...

    自己总结css笔记

    转换过程中,需注意字符集的兼容性和正确性,以避免乱码问题。 ### HTML文档结构与元数据 #### 文档类型声明(DOCTYPE) 用于告知浏览器使用哪种规范解析页面。例如: - `&lt;!DOCTYPE html&gt;`:HTML5文档类型,最...

    Freemarker 学习笔记一 【乱码解决】

    在使用Freemarker的过程中,遇到乱码问题是一个常见的挑战,特别是当处理不同编码格式的数据时。本篇文章将探讨如何解决Freemarker中的乱码问题,并提供相关源码和工具的使用技巧。 首先,乱码通常源于字符编码不...

    python笔记大全

    此外,针对中文输出的问题,提供了使用编码声明和设置的解决方案。 6. Python与Web服务器的整合: 笔记还介绍了如何将Python与Apache Web服务器结合。通过mod_python模块,可以让Apache服务器直接处理Python代码,...

    二维码学习备忘笔记

    二维码是一种二维条形码,由黑白相间的模块组成,可以存储大量的数据,包括数字、字母、汉字等。相比于传统的条形码,二维码在相同的空间内可以存储更多信息,并且能够被快速读取。二维码的设计基于错误纠正机制,...

Global site tag (gtag.js) - Google Analytics