hechengjin 发表于 2016-6-14 09:34:53

字符集和编码 字节序

http://www.cnblogs.com/foreach-break/p/external_sort_what_to_take_into_account.html



字符集和编码为什么要考虑文件的编码?
当你将文件从阿拉伯传到中国,告诉你的中国朋友要进行一个外部排序,你的中国朋友也许会傻:
http://img.blog.csdn.net/20150614231450430上面是什么?乱码.
你也可以这样体验乱码:echo "数" > t.txticonv -f UTF-8 -t UNICODE t.txt��pe好了,你知道了如果不知道文件的编码,你可能会解析到乱码.字符集是什么?charset - > char-set,字符的集合.比如UNICODE、ASCII编码是什么?encoding,字符的表示.比如UTF-8、ASCII字符集和编码的关系你晕了,我也晕了,ASCII码怎么既是字符集又是编码?历史上,字符集和编码是同义词,实际却又不尽相同,没有一个规范地定义,那怎么理解呢?字符集,往往强调其所“支持”的字符范围,集外的字符它不支持.集合就有一个边界,边界内的我给个表示,边界外的我不知道怎么表示。编码,往往强调针对某个字符集的字符,我这么去转换表达为机器可理解的方式-二进制,如果对某个字符集的字符,我的转换方式和其一致,那么我既是编码也是字符集,否则我就只是一种字符集的转换格式。那么,UNICODE是字符集,它所支持的字符,在它内部,也有个表示,这种表示是不是一种编码?毫无疑问,是一种编码。UTF-8是一种编码,是对UNICODE的一个变长实现,这种编码和UNICODE编码是什么关系?转换关系。所以看编码还是字符集,往往要看“语境”。举个简单的例子:汉字:“数”
编码/字符集进制值
UNICODE166570
UNICODE2110010101110000
UTF-816E6 95 B0
UTF-82111001101001010110110000
这个例子,你可以这样体验:/// 看utf-8echo "数" > t.txthexdump -xv -C t.txt0000000    95e6    0ab0                                                00000000e6 95 b0 0a                                       |....|00000004/// 看unicodeiconv -f utf-8 -t unicode t.txt | hexdump -xv -C0000000    feff    6570    000a                                        00000000ff fe 70 65 0a 00                                 |..pe..|00000006字节序如果你注意到汉字“数”经过UTF-8编码后的16进制是E6 95 B0,再给它后面加个换行是E6 95 B0 0A,你用下面的方法会看到:hexdump -xv -C t.txt0000000    95e6    0ab0                                                00000000e6 95 b0 0a                                       |....|00000004按双字节(16位)的方式解析,你得到是95 E6 0A B0,你一定很费解,然并卵,这种费解的根源就是字节序造成的。字节序就是字节的顺序,如果按照双字节(16位)的方式解析E6 95 B0 0A,那么读16位,得到E6 95,字节序反一下,得到95 E6,再读16位,得到B0 0A,字节序反一下,得到0A B0,合起来就是95 E6 0A B0。这种“反字节序”就叫Little-Endian,小端或者小尾。大端(Big-Endian | BE)http://img.blog.csdn.net/20150615000956218
注:图片来自wiki从上图可以看出,一个数的最高字节被放在内存的低地址处:
0A -> a + 0,这种方式就是大端(Big-Endian),数的最高字节叫作Most Significant Byte,这个你可以称作最高有效字节或者最重要的字节,为什么最重要呢?对于1个数来讲,它的最高字节能反映这个数的符号(正负),也比低位字节更能代表这个数的大小。大端存储的特点也决定了它的优点,就是近似估计一个数的大小和符号,只需要取最高字节即可。小端(Little-Endian | LE)反之,如果一个数的最低字节被放在内存的低地址处:
0D -> a + 0,这种方式就是小端(Little-Endian),数的最低字节叫作Least Significant Byte,可以称作最低有效字节或者最不重要的字节。32位/64位地址下:
10进制16进制位数(bits)/字节数(bytes)BELE
1684961410A 0B 0C 0D32/40A 0B 0C 0D0D 0C 0B 0A
30850C 0D16/20C 0D0D 0C
很显然,大端存储符合我们人类从左往右书写或阅读的习惯,为什么又要出一个如此麻烦的小端存储呢?小端存储,取数的时候可以这样:
a + 0 -> 第一个字节
a + 1 -> 第二个字节
a + 2 -> 第三个字节
a + 3 -> 第四个字节
一个基址a,+不同的偏移即可完成不同精度的取数操作,high么?如何区分大端还是小端?如果你注意到:/// 看unicodeiconv -f utf-8 -t unicode t.txt | hexdump -xv -C0000000    feff    6570    000a                                        00000000ff fe 70 65 0a 00                                 |..pe..|00000006那么前2个字节feff就表示了小端存储,很简单,fe < ff,这2个字节叫作Byte Order Mark,称字节序标记,不仅可以用作区分文件是大端/小端存储,还可以表示编码。至于编程的方式区分大端小端,这个如果你谨记字节序的含义相信不难写出代码:      /// java获取字节序BE/LE      Field us = Unsafe.class.getDeclaredField("theUnsafe");      us.setAccessible(true);      Unsafe unsafe = (Unsafe)us.get(null);      long a = unsafe.allocateMemory(8);      ByteOrder byteOrder = null;      try {            unsafe.putLong(a, 0x0102030405060708L);            byte b = unsafe.getByte(a);            switch (b) {            case 0x01: byteOrder = ByteOrder.BIG_ENDIAN;   break;            case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN;break;            default:                assert false;                byteOrder = null;            }      } finally {            unsafe.freeMemory(a);      }      System.out.println(byteOrder.toString());
用C/C++就更简单了,一个union就搞定了.字节序影响了什么?字符集和编码如果搞错,会导致乱码,字节序搞错,会导致错码,很显然0C0D和0D0C不是同一个数,不是么?

页: [1]
查看完整版本: 字符集和编码 字节序