UTF-8和Unicode编码
常用的能够保存汉字的编码表有UTF-8、GBK等。需要注意,无论文件使用的是什么编码格式,读取到Java程序中,所有的字符都是用Unicode编码表示(Java中所有的字符内容都使用char类型表示,一个char代表16位、2Byte无符号Unicode码值)。
Unicode表示的范围比UTF-8要大,但是Unicode只需要2字节,而UTF-8最多可能需要3字节,GBK一个汉字占2Byte,UTF-8一个汉字占3Byte
UTF-8主要解决了传输过程中资源的浪费。
传输的是一些英文字母、阿拉伯数字等内容,但是由于Unicode的规定,所有的字符都固定用2字节表示。英文字母、阿拉伯数字这些本来用一个字节就可以表示出来的字符也需要使用两个字节表示。这样就会造成资源浪费。
例如
原 | Unicode编码 | 二进制表示 |
---|---|---|
f | \u0066 | 00000000 01100110 |
l | \u006c | 00000000 01101100 |
o | \u006f | 00000000 01101111 |
w | \u0077 | 00000000 01110111 |
e | \u0065 | 00000000 01100101 |
r | \u0072 | 00000000 01110010 |
是 | \u662f | 01100110 00101111 |
1 | \u0031 | 00000000 00110001 |
朵 | \u6735 | 01100111 00110101 |
花 | \u82b1 | 10000010 10110001 |
我们可以看出对于英文与阿拉伯数字,其高8位全为0,会极大的浪费空间。
UTF-8解决这个问题的思路是能用一个字节表示的就用一个字节,一个字节不够的,再用两个字节。
规定:
-
如果一个字符只占用一个字节,那么这个字节的第一位就必须为0。
0xxx xxxx
-
如果一个字符占用了两个字节,那么高八位前两位必须都为1、第三位为0。低八位前两位必须为10。
110x xxxx 10xx xxxx
-
如果一个字符占用了三个字节,那么高八位前三位必须是111,第四位是0。中八位和低八位前两位都是10。
1110 xxxx 10xx xxxx 10xx xxxx
假设从某个文件中读取出如下字节串:
11011010 10110010 01101101 11101111 10010010 10101010
根据UTF-8的规则,就可以把它识别为:
-- | -- | -- |
---|---|---|
11011010 10110010 | 01101101 | 11101111 10010010 10101010 |
双字节 | 单字节 | 三字节 |
11010 110010 | 1101101 | 1111 010010 101010 |
识别时候将标识位(我也不知道具体叫啥)去掉,也就是前面的0,110,1110 | ||
也就是将如上表格的第二行的黑体字去掉,于是变成了第四行 | ||
对于如上的“flower是1朵花”,例如“是”则将二进制表示拼接进1110 xxxx 10xx xxxx 10xx xxxx中,并且从低位开始,高位补0 |
原 | 二进制表示 | UTF-8编码 |
---|---|---|
f | 00000000 01100110 | 01100110 |
l | 00000000 01101100 | 01101100 |
o | 00000000 01101111 | 01101111 |
w | 00000000 01110111 | 01110111 |
e | 00000000 01100101 | 01100101 |
r | 00000000 01110010 | 01110010 |
是 | 01100110 00101111 | 11100110 10011000 10101111 |
1 | 00000000 00110001 | 00110001 |
朵 | 01100111 00110101 | 11100110 10011100 10110101 |
花 | 10000010 10110001 | 11101000 10001010 10110001 |
在将来解析的时候
判断若开头是0,则表示是一个字节组成;
若开头是1110,则表示是由三个字节组成,并且把标识位(就那个1110 xxxx 10xx xxxx 10xx xxxx的1与0)去掉,
剩下的拼接成一个二进制字符串,然后再将其转化成16进制,则成为Unicode编码