在前面的字符集编码系列中,已经探讨了几大主要的字符集编码。在此基础之上,这里将进一步探讨编码的应用及乱码的根源,咱们先从基本的文件提及。html
文件(内容)就是字节序列。文本文件也是文件,因此它也是字节序列。java
一般说到文件时,指的是文件内容,但文件还有文件名,文件名与文件内容是分开存储的。windows
你能够在硬盘上新建一个文件,它的大小为0.以下:api
但它是有文件名的,好比上述的“新建文本文档.txt“,保存这些名字天然也要占用空间,只不过它与文件内容是分离的。架构
这些由操做系统的文件系统模块负责。oracle
文件名是一段文本,所以它会涉及字符集编码。测试
文件内容则视状况而定:编码
1. 文本文件,确定会涉及字符集编码。spa
常见的好比txt,html,xml以及各类源代码文件等等。操作系统
2. 非文本文件,好比图片文件jpg,gif之类,天然跟字符集编码无关了。
有些文件,好比Word的doc之类的,混合了图片跟文本在里面,能够想像,其中的文本部分天然也会牵涉到字符集编码的问题,只不过这些编码不禁咱们去控制,咱们一般也无须去关心。
文件名是一串文本,所以它必然涉及某种字符集编码,只不过这种编码是由操做系统决定的,咱们无权干预。
那么,它用的是什么编码呢?在Windows下,能够简单作些实验。咱们能够弄些奇怪的文件名如“★★★★.txt”,以下:
结果也能保存。这些字符只在Unicode中才有,因此它确定不是用的GBK之类的。
Windows下NTFS架构文件名使用UTF-16编码。但对于FAT之类的,则是所谓的“OEM character set”。
MSDN上的原文以下:“NTFS stores file names in Unicode. In contrast, the older FAT12, FAT16, and FAT32 file systems use the OEM character set”(NTFS使用Unicode存储文件名。与此相对,老的FAT12,FAT16和FAT32文件系统使用OEM字符集).参见http://msdn.microsoft.com/en-us/library/windows/desktop/dd317748%28v=vs.85%29.aspx
注:在Windows语境中,UTF-16一般叫成Unicode。
结合实验的结果,能够肯定,Windows使用UTF-16对文件名进行编码。(个人系统是Win 7,文件系统为NTFS)
不过,不一样的系统平台可能使用了不一样的编码。好比最新的Linux平台对文件名采用了UTF-8编码,但早期的则很差说,甚至没有一个标准。
若是你不是Windows平台,你也能够简单作些实验来大体猜想一下文件系统使用的编码。
因为对文件名没有一个统一的编码,不一样系统平台间交换文件时,中文文件名极易发生乱码现象。好比FTP上传,网页文件上传及下载等状况下常常能遇到文件名乱码。
不过,须要注意的是,交换过程当中,文件内容不会发生任何改变。即使是文本文件,也彻底是字节传送,不会涉及任何的编解码。
你可能碰到过这样的事,把一个文本文件从Windows平台上传到Linux平台,并在Linux平台下打开时发现乱码了,但这不意味着文件内容有了什么变化,一般的缘由是你的文件是用GBK编码的,但Linux平台下打开时它缺省可能用的是UTF-8编码去读取,所以,你只要调整成正确的编码去读取便可。
在这里,咱们讨论了文件名的编码,以后,如无特别说明,谈到编码时均指对文件内容的编码。一般,这是咱们更为关心的内容。
一般,说到字符集编码都是对文本文件而言的,但非文本文件也是可能用到字符集编码的。
好比,Word用什么编码?word生成的doc或者docx虽然不是文本文件,但咱们能够想像,它里面可能有图像,又有文字。其中的文字天然也会用到某种编码。只不过,这些都不须要咱们去操心。
下面是一个实验,新建一个空白的doc文档,录入几个简单字符”Hello你好”
保存成doc文件,再用notepad++打开,以十六进制形式查看:
如上图,搜索到hello几个关键字,咱们知道,“H”的码点是U+0048,而“你”的码点则是U+4F60,因此,很显然,用的是UTF-16 LE(Little Endian,小端序)
关于端序及BOM的相关话题,可参见字符集与编码(七)——BOM
注:这只是我我的在本机测试的结果,不表明广泛的结论,不一样平台不一样版本下的可能会有差别,谁知道呢?我没有去研究过doc文件格式的规范,这个doc我仍是用WPS生成的!
又好比,Java中的class文件,它也不是文本文件,一般称为字节码文件。但它里面也会保存String的常量,这天然又要牵涉到编码。实际用的是所谓的“modified UTF-8”编码。
简单创建一个java文件,定义一个string常量”Hello你好“:
public class Foo { static final String HI = "Hello你好"; }
保存并用javac命令编译获得class文件,再次用notepad++打开并以十六进制形式查看:
搜索到Hello几个关键字,紧接在它们后面的”e4 bd a0“就是”你“的UTF-8编码了。
在前面的字符集与编码(四)——Unicode中,曾提到过,汉字的UTF-8编码一般都是以e打头,形如ex xx xx这样,这是经常使用汉字UTF-8编码的一个重要特征。
这个”modified UTF-8”编码与UTF-8相似,但有一些差异,它的名字也暗示了这一点。
好比对于U+0000它用了两字节来编码;
还有对U+FFFF以上的字符它采用了6字节编码而非正常UTF-8的四字节编码,实质是对代理对(surrogate pairs)的值进行编码。
详情可参见http://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#modified-utf-8
文本文件也是文件,因此它也是字节序列。当读取一个文本文件时,最重要的是肯定它所使用的编码,只有这样才能正确的解码。
因为牵涉的状况较多,咱们将在下一篇讨论这一问题。