Java GBK中文乱码问题分析

在io相关的操做中常常会出现乱码问题html

 

好比在一个txt文件中按GBK编码保存内容"淘!我喜欢!"java

而后用RandomAccessFile类读取并打印一行。后端

RandomAccessFile raf = new RandomAccessFile("D:\\1.txt","r");
System.out.print(raf.readLine());

 

打印结果显示乱码:数组

 

在网上查询到加入相关编码解码操做后能够解决该问题数据结构

RandomAccessFile raf = new RandomAccessFile("D:\\1.txt","r");
System.out.print(new String(raf.readLine().getBytes("ISO-8859-1"),"gbk"));

 

 

问题:app

在这个过程当中发生了什么?dom

 

要解答这个问题首先要知道编码和解码的概念以及产生的缘由:编辑器

为何要编码编码

 

不知道你们有没有想过一个问题,那就是为何要编码?咱们能不能不编码?要回答这个问题必需要回到计算机是如何表示咱们人类可以理解的符号的,这些符号也就是咱们人类使用的语言。因为人类的语言有太多,于是表示这些语言的符号太多,没法用计算机中一个基本的存储单元—— byte 来表示,于是必需要通过拆分或一些翻译工做,才能让计算机能理解。咱们能够把计算机可以理解的语言假定为英语,其它语言要可以在计算机中使用必须通过一次 翻译,把它翻译成英语。这个翻译的过程就是编码。因此能够想象只要不是说英语的国家要可以使用计算机就必需要通过编码。这看起来有些霸道,可是这就是现 状,这也和咱们国家如今在大力推广汉语同样,但愿其它国家都会说汉语,之后其它的语言都翻译成汉语,咱们能够把计算机中存储信息的最小单位改为汉字,这样 咱们就不存在编码问题了。spa

 

因此总的来讲,编码的缘由能够总结为:

    1.计算机中存储信息的最小单元是一个字节即 8 个 bit,因此能表示的字符范围是 0~255 个。

    2.人类要表示的符号太多,没法用一个字节来彻底表示。

    3.要解决这个矛盾必须须要一个新的数据结构 char,从 char 到 byte 必须编码。

名词解释:

解码:将byte数组转为char数组。

编码:将char数组转为byte数组。

 

计算机存储的基本单位是byte,但打开一个文件时文件编辑器已经作了解码的工做。

如下为解码过程描述

文件实际存储的内容是(如下为16进制):

打开文件后看到的内容为

须要详细说明如下代码的处理过程

RandomAccessFile raf= new RandomAccessFile("D:\\1.txt","r");
System.out.print(raf.readLine());

 

首先看一下java.io.RandomAccessFile#readLine方法的源码

public final String readLine() throws IOException {
        StringBuffer input = new StringBuffer();
        int c = -1;
        boolean eol = false;
        while (!eol) {
            switch (c = read()) {
            case -1:
            case '\n':
                eol = true;
                break;
            case '\r':
                eol = true;
                long cur = getFilePointer();
                if ((read()) != '\n') {
                    seek(cur);
                }
                break;
            default:
                input.append((char)c);
                break;
            }
        }
        if ((c == -1) && (input.length() == 0)) {
            return null;
        }
        return input.toString();
    }

 

主要关注read()部分和(char)c,read()是一个本地方法,做用是从文件中读取一个byte字节。

(char)c是将变量c从byte类型转换为char类型,这是一个解码操做。

问题:此处是以什么格式进行解码?

解码格式是ISO-8859-1

raf.readLine()的处理过程以下

那么

new String(raf.readLine().getBytes("ISO-8859-1"),"gbk")

 

这行代码作了什么

首先readLine()按行一字节一字节地读取文件中的数据,而且按ISO-8859-1进行解码拼成char数组,而后getBytes("ISO-8859-1")对拼成后的char数组按ISO-8859-1进行编码获取byte数组,最后new String(string,"gbk")对编码后的byte数组用gbk格式进行解码成char数组。

 

参考资料:深刻分析 Java 中的中文编码问题

 

遗留问题:

一、如何避免重复转码。

二、RandomAccessFile的readLine()效率很是低,如何提升效率。

 

 

JAVA后端qq交流群:477318923

相关文章
相关标签/搜索