02-字符集讲解

字符集讲解(ASCII,GBK)

乱码案例

/Users/chenjp/tmp/yey/b.txt 文件内容

杀菌~ABC的

读取文件的代码

public class Demo {

    public static final String FILE_OUTPUT_PATH = "/Users/chenjp/tmp/yey/b.txt";

    public static void main(String[] args) throws IOException {
        FileInputStream fos = new FileInputStream(FILE_OUTPUT_PATH);
        int b ;
        while((b=fos.read())!=-1){
            System.out.print((char) b);
        }
        fos.close();
        System.out.println();
    }

}

读取文件的输出结果

Connected to the target VM, address: '127.0.0.1:62594', transport: 'socket'
杀菌~ABC的
Disconnected from the target VM, address: '127.0.0.1:62594', transport: 'socket'

Process finished with exit code 0

计算机存储规则

在计算机中,任意数据都是以二进制的形式来存储的,单位bit(比特),8bit是1 byte(字节),字节是计算机最小的存储单元。存储英文只需要1个字节就行,中文需要2字节。

ASCII 英文

GBK 英文&中文

Unicode 英文&中文

ASCII

英文 a 存储时对应ASCII码是97,对应二进制110 0001,存储时是以1字节存储,需要8位的二进制,所以要在二进制码前面补0,补齐8位 ,即0110 0001

读取时,是读取0110 0001然后解码得到十进制97,查询ASCII码得到读取的英文a

GBK

国家在1980年发布了国家标准的信息交换用汉字编码字符集 GB 2312-80,收录了7445个图形字符,其中包括6763个简体汉字。

台湾地区繁体字在BIG5字符集中收录,共收录了13053个中文字,1984年实施。

2000年3月17日发布了GBK字符集,收录了21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。

在windows系统中默认使用的就是GBK,系统显示为ANSI,所以ANSI就是GBK。

GBK存储英文

GBK也是完全兼容 ASCII 的。存储英文时与 ASCII 一样。二进制前面补 0 。

GBK存储汉字

存储一个汉字时使用两个字节进行存储

前面的第一个字节叫高位字节,后面的叫地位字节。

高位字节二进制一定以 1 开头,转成十进制之后是一个负数

这里高位一定要以1开头是为了区分中文和英文,在读取二进制的时候,读取到1开头的字节就知道后面两个字节表示一个汉字,如果读取到0就表示当前字节是表示英文的。

Unicode

Unicode字符集,国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。

存储规则

a --> 查询Unicode. --> 97 --> 编码

UTF(Unicode Transfer Format ) Unicode转换格式

采用UTF-16编码规则:用2~4个字节保存 a -> 0000 0000 0110 0001

采用UTF-32编码规则:固定用4个字节保存 a -> 0000 0000 0000 0000 0000 0000 0110 0001

采用UTF-8编码规则: 用1~4个字节保存

在UTF-8中,

ASCII中的所有字符都适用1个字节表示, 0xxx xxxx (ASCII码)

叙利亚等国家语言使用2字节表示, 110x xxxx 10xx xxxx

中文等国家语言使用3个字节表示, 1110 xxxx 10xx xxxx 10xx xxxx

也有用4个字节表示的语言。 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx

存储汉字

查询Unicode编码集得到27721,对应 0110 1100 0100 1001

再进行UTF-8编码 , 1110 0110 1011 0001 1000 1001

这里的填补规则就是将0110 1100 0100 1001填补到1110 xxxx 10xx xxxx 10xx xxxx中的x部分

为什么会有乱码

原因1:读取数据时未读完整个汉字

比如说读取 1110 0100 1011 1101 1010 0000时,这应该读取出来是一个可查询到汉字的编码,但是没有将这3个字节读取完,只读取了一个字节 1110 0100,这个二进制表示-28,但是-28在编码集中查询不到对应的符号,这时操作系统就会显示 ???或者其他符号,这就造成了乱码。

原因2: 编码和解码时的方式不统一

比如说存储汉字时用UFT-8进行存储的,这时采用3个字节表示这个汉字,但是解码的时候使用了GBK进行了解码,但是GBK中汉字是2个字节表示的,只会读取编码后的3个字节的前2个字节进行解码,这时候编码和解码的就会出现问题,导致乱码。

如何不产生乱码

  1. 不要使用字节流读取文本文件
  2. 编码解码时使用同一个码表,同一个编码方式

字节流读取中文会乱码,但是为什么拷贝不会乱码呢?

这是因为所有的字节都拷贝过去了,并且源文件的写入方式和拷贝后的文件打开方式使用的是同一种编码方式,所以就不会乱码。

Java中的编码方式

String类中的方法 说明
public byte[] getBytes( ) 使用默认方式进行编码
public byte[] getBytes( String charsetName ) 使用指定方式进行编码

Java中的解码方式

String类中的方法 说明
String( byte[ ] bytes ) 使用默认方式进行解码
String( byte[ ] bytes , String charsetName ) 使用指定方式进行解码

编码解码代码演示

public class BianMa {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "ai你哟";
        byte[] bytes = str.getBytes();
        System.out.println("编码结果:");
        System.out.println("UTF-8编码  "+Arrays.toString(bytes));
        byte[] bytes1 = str.getBytes("GBK");
        System.out.println("GBK编码    "+Arrays.toString(bytes1));

        System.out.println("解码结果: ");
        String string = new String(bytes);
        System.out.println("UTF-8解码原UTF-8  "+string);
        String string1 = new String(bytes,"GBK");
        System.out.println("GBK解码原UTF-8    "+string1);
        String string2 = new String(bytes1);
        System.out.println("UTF-8解码原GBK  "+string2);
    }

}

-

-

-

-

-

-

-

-

-

-

-

-

-

你可能感兴趣的:(java,开发语言)