Java IO(01) 编码问题(一)

IO是Java中的一块比较重要的知识,在日常开发中应用广泛,现对Java IO知识进行整理归纳。

在IO之前呢,用几篇文章介绍一下Java中的编码以及File类的基本使用。本篇文章先来简单介绍编码。

为了更直观的解释各种编码以及对他们进行比较我们用几个简单的例子来说明。

代码1

/**
 * 测试不同的编码格式,为方便显示,将字节序列以16进制形式显示,并且输出只显示有效的低8位
 * 具体方式是Integer.toHexString(byte[n] & 0xff)
 */
public class Encode {
    public static void main(String[] args) throws Exception{
        String s = "测试ABC";

        //使用IDE默认的编码格式进行字节序列转换,这里的默认编码方式是"utf-8"
        byte[] b = s.getBytes();
        System.out.print("默认utf-8编码:");
        for(byte bt : b) {
            System.out.print(Integer.toHexString(bt & 0xff) + " ");
        }
    }
}
运行结果:

默认utf-8编码:e6 b5 8b e8 af 95 41 42 43 

上面这段代码中字符串s中包含了中英文的内容,下面仍旧用这个字符串进行举证。通过上面这个例子可以看出来字符串“测试ABC”进行了字节序列转换后变成了一串二进制,我们用十六进制的形式将其输出显示,最终运行结果如上。这段字符串占据了9个字节,一个汉字用三个字节表示,一个英文字符用一个字节表示。s.getBytes()可以看出,我们没有设置任何编码格式,使用的IDE默认的编码格式进行字节序列转换,这里默认的编码格式是“utf-8”格式。


代码2

/**
 * 测试不同的编码格式,为方便显示,将字节序列以16进制形式显示,并且输出只显示有效的低8位
 * 具体方式是Integer.toHexString(byte[n] & 0xff)
 */
public class Encode {
    public static void main(String[] args) throws Exception{
        String s = "测试ABC";

        //显性地设置"utf-8"编码,由于IDE默认也是该编码方式,所以输出结果应该相同
        byte[] b2 = s.getBytes("utf-8");
        System.out.print("显性设置utf-8编码: ");
        for (byte bt : b2){
            System.out.print(Integer.toHexString(bt & 0xff) + " ");
        }
    }
}
运行结果:

显性设置utf-8编码:  e6 b5 8b e8 af 95 41 42 43 

代码2和代码1的区别就是s.getBytes("utf-8"),这样的更明显地对字节序列转换地编码格式做出了要求,这里设置成“utf-8”格式,从结果上看和代码1的运行结果没有任何区别,实际上本来也不会有区别,这里也证明了默认的编码格式是“utf-8”。

代码3

/**
 * 测试不同的编码格式,为方便显示,将字节序列以16进制形式显示,并且输出只显示有效的低8位
 * 具体方式是Integer.toHexString(byte[n] & 0xff)
 */
public class Encode {
    public static void main(String[] args) throws Exception{
        String s = "测试ABC";

        //进行"gbk"格式的字节序列转换
        byte[] b1 = s.getBytes("gbk");
        System.out.print("gbk编码:");
        for (int i = 0; i < b1.length ; i++) {
            System.out.print(Integer.toHexString(b1[i] &0xff) + " ");
        }
    }
}

运行结果:

gbk编码:b2 e2 ca d4 41 42 43 

代码3换了一种编码格式,也是我们经常见到的编码格式“gbk”,可以看出来它与“utf-8”编码格式的区别,“gbk”编码中文字符占两个字符,英文占一个字符,所以这段字符串使用这种编码就占据了7个字节。

代码4

/**
 * 测试不同的编码格式,为方便显示,将字节序列以16进制形式显示,并且输出只显示有效的低8位
 * 具体方式是Integer.toHexString(byte[n] & 0xff)
 */
public class Encode {
    public static void main(String[] args) throws Exception{
        String s = "测试ABC";

        //java属于双字节编码,一个字符占两个字节,这种编码格式就是"utf-16be"
        byte[] b3 = s.getBytes("utf-16be");
        System.out.print("java双字节utf-16be编码:");
        for (byte bt : b3){
            System.out.print(Integer.toHexString(bt &0xff) + " ");
        }
    }
}
运行结果:

java双字节utf-16be编码:6d 4b 8b d5 0 41 0 42 0 43 

代码4展示了java的双字节编码,根据运行结果可以看出,无论中文还是英文,都占据了两个字节,这就是“utf-16be”双字节编码。

代码5

/**
 * 测试不同的编码格式,为方便显示,将字节序列以16进制形式显示,并且输出只显示有效的低8位
 * 具体方式是Integer.toHexString(byte[n] & 0xff)
 */
public class Encode {
    public static void main(String[] args) throws Exception{
        String s = "测试ABC";

        //java属于双字节编码,一个字符占两个字节,这种编码格式就是"utf-16be"
        byte[] b3 = s.getBytes("utf-16be");
        System.out.print("java双字节utf-16编码:");
        for (byte bt : b3){
            System.out.print(Integer.toHexString(bt &0xff) + " ");
        }
		/**
        * 当一个 字节序列想变成字符串,那么字节序列是什么编码格式,
        * 则转换成字符串也要用这种编码形式,否则就会出现乱码的情况
        */
        //按照原编码格式"utf-16be"进行转换
        String s3 = new String(b3,"utf-16be");
        System.out.println();
        System.out.println("utf-16be进行转换:"+s3);

        //"utf-16be"编码格式的字节序列使用IDE默认的"utf-8"格式进行转换结果会乱码
        String s4 = new String(b3);
        System.out.println("使用IDE默认的utf-8格式进行转换:"+s4);
    }
}
运行结果:

java双字节utf-16be编码:6d 4b 8b d5 0 41 0 42 0 43 

utf-16be进行转换:测试 ABC

使用IDE默认的utf-8格式进行转换:mK�� A B C

代码5表示的是将经过“utf-16be"编码格式后生成的字节序列进行字符串的转换,运行结果可以看出来,通过转换成字节序列的编码方式”utf-16be“进行转换的结果和源字符串相同,而通过IDE自身默认的”utf-8“编码方式进行转换,则无法还原原字符串。所以当字节序列想变回字符串,那么字节序列是什么编码格式,则转换成字符串也要用这种编码形式,否则就会出现乱码的情况。

通过以上五段代码,对编程中的编码问题是不是有了一些概念。其实文本文件本身存放就是字节序列,而且可以是任意编码形式的字节序列。需要注意的是,假如我在中文机上创建一个文本文件,这个文本文件只能够识别ANSI这种编码格式的字节序列,这里尤其强调是创建的文本文件,加入我从它处复制到中文机上一个文本文件,这个文本文件是不需要必须是ANSI编码格式的,可以是任意编码形式的文本文件,当复制到中文机上的时候,可以自动完成识别。上面整段话不太好理解,只要记住,向中文机复制文件是不需要关心它的编码格式的,但是创建的话,只能是ANSI编码格式下进行创建,如果你创建一个其它格式的,就会出现乱码。

另外还需要关注一点,在Java中,我们可以看到代码1下表示工程下默认的编码格式是utf-8,但是如果在另一个工程中是采用的其它编码格式,两个工程间的文本文件是无法直接复制的,因为无法识别,会出现乱码,当然,如果你直接复制文本内容的话,可以做到自动识别,这是没有问题的。

这几个例子就先说到这里,在《Java IO(01)编码问题(二)》中会更加详细具体介绍编码问题,包括二进制中的一些基础回顾,例如位运算,大小端等。

参考内容:

https://www.imooc.com/video/1832/0

https://zhidao.baidu.com/question/1637850644089866940.html

http://www.cnblogs.com/vhua/p/idea_1.html


猜你喜欢

转载自blog.csdn.net/adelaide_guo/article/details/78750866