【JAVA入门】Day39 - 字符集
文章目录
- 【JAVA入门】Day39 - 字符集
- 一、常见的字符集
- 二、计算机的 GBK 存储规则(英文)
- 三、计算机的 GBK 存储规则(汉字)
- 四、Unicode 字符集
- 五、乱码
- 六、Java 中编码的方法
在计算机当中,任意数据都是以二进制形式来存储的。一个二进制位我们叫做 1 bit 。我们把 8 bit 合成一个新的计量单位叫做字节,一个字节能存储 2^8 = 256 种数据,英文是 byte 。字节是计算机当中最小的存储单元。
要存储英文字母,一个字节就足够了。在 ASCII 码表中记录了 128 个数据,这128个数据已经包含了 26 个英文字母和一些常用的英文标点符号,在表达英文日常需求时已经足够使用,而一个字节能存储 256 种数据编码,是这个表中字符的两倍,因此一个字节就可以存储英文。
计算机在存储 ASCII 码表中的字符时,并不是直接存储字符的二进制值,而是用前面补0的方式将字符补齐8位再存。
在读取时,直接读取这个二进制编码,然后转化成十进制,再去到 ASCII 码表里面查表,得到英文。
但是 ASCII 这 128 个字符明显不能满足其他国家字符编码的要求,尤其是汉字,因此我们国家推出了自己的字符集。
一、常见的字符集
1. GB2312 字符集:1980年发布,1981年5月1日实施的简体中文汉字编码标准,收录7445个图形字符,其中包括6763个简体汉字。
2. BIG5 字符集:台湾地区繁体中文标准字符集,共收录13053个中文汉字,1984年实施。
3. GBK 字符集:2000年3月17日发布,收录21003个汉字,包含国家标准 GB13000-1 中的全部中日韩汉字,和 BIG5 编码中的所有汉字。在 Windows 系统中默认使用的字符集就是 GBK。GB 代表国标,K 代表扩展。在微软系统中起的名字叫 ANSI 。
4. Unicode 字符集:国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。
二、计算机的 GBK 存储规则(英文)
GBK 编码是完全向下兼容 ASCII 码的。英文字母用一个字节来存储,完全兼容 ASCII 。在存储字符时,不足8位在前面补0。
三、计算机的 GBK 存储规则(汉字)
一个汉字的长度是 2 个字节(16 bit)。第一个字节被称为高位字节,第二个字节被称为低位字节。高位字节的二进制一定以1开头,转成十进制后是一个负数。字节码的二进制格式在存储到计算机中时,不需要变动。计算机底层以编码最高位是 0 还是 1 来区分中文字符和英文字符。
计算机在读取文件时,直接将汉字的二进制编码解码,然后查询 GBK 即可得到相应的汉字。
四、Unicode 字符集
Unicode 字符集是统一码联盟发布的一个统一字符集,包含了世界上大部分国家的文字字符。Unicode 在编码时,有多种编码方案。早前有 UTF-16、UTF-32 等编码方案,后都已废弃。
后来出现了 UTF-8 编码规则,它是一种针对 Unicode 字符集的可变长度编码规则,它规定一个字符用 1~4 个字节保存。
UTF-8 规定,如果是 ASCII 码中有的字符,就用 1 个字节存储;如果是拉丁文、希伯来文等文字,用 2 个字节存储;如果中日韩文字、东南亚文字、中东文字,用 3 个字节存储;其他语言,用 4 个字节存储。四种编码的数字补充格式如下:
五、乱码
乱码出现的原因往往是:读取数据时未读完整个汉字。
如果用字节流读取 Unicode 时,字节流一次只能读取一个字节,而一个汉字占用 3 个字节,所以导致读取不完整,出现乱码。
另一个可能的原因是:编码和解码的方式不统一。UTF-8 编码规则规定汉字利用 3 个字节进行存储,如果我们在解码时使用了其他的解码规则(比如 GBK 解码),就会导致汉字读取不全,变成了其他字符。
因此,我们要尽量避免乱码的产生:
1.不要用字节流读取文本文件。
2.编码解码时使用同一个码表,同一种编码方式。
但是值得一提的是,使用字节流方式拷贝文件时,由于它是逐个字节进行拷贝,到最后形成的副本和原文件是一模一样的,因此这种方式生成的新文件不会产生乱码。
六、Java 中编码的方法
在 Java 中,我们可以使用一些方法自己查看字符编码和解码的方式。
package IOByteStream;import java.io.UnsupportedEncodingException;
import java.util.Arrays;public class ByteStreamDemo14 {public static void main(String[] args) throws UnsupportedEncodingException {//1.编码String str = "ai你哟";byte[] bytes1 = str.getBytes(); //使用默认编码方式 UTF-8System.out.println(Arrays.toString(bytes1)); //[97, 105, -28, -67, -96, -27, -109, -97] UTF-8 占8个字节byte[] bytes2 = str.getBytes("GBK"); //使用 GBK 编码方式System.out.println(Arrays.toString(bytes2)); //[97, 105, -60, -29, -45, -76] GBK 占6个字节//2.解码String str2 = new String(bytes1); //默认使用 UTF-8 解码System.out.println(str2);String str3 = new String(bytes1, "GBK"); //自己设定使用 GBK 解码(但是这个字节数组的编码方式是 UTF-8,会产生乱码)System.out.println(str3);}
}