Java字节流 字符流(三)

其实,一切都是字节流,没有字符流这个东西。字符只是根据编码集对字节流翻译之后的产物。

代码分析

看下面这段代码:

 public class JavaEncode {

    public static void main(String[] args) throws IOException {
        
       // test 1
        InputStream inputStream = new FileInputStream(new File("demo.txt"));
        byte[] bytes = new byte[6];
        inputStream.read(bytes);
        System.out.println(HexUtil.encodeHex(bytes));

        String utf8Str = new String(bytes, "gbk");
        System.out.println(utf8Str);

       // test 2
        inputStream = new FileInputStream(new File("demo.txt"));
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "GBK");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String cs = bufferedReader.readLine();
        System.out.println(cs);

    }
}

其中demo.txt中存储的文本为:


image.png

另外文件编码格式是UTF-8。

输出的结果为:

e4b8ade59bbd
涓浗
涓浗

其中e4b8ade59bbd为“中国”两个汉字的UTF-8编码,第二行和第三行为乱码,两次输出的乱码是一样的。

对于test 1

  • 首先创建了一个demo.txt文件的输入流(类似于一个管道)
  • 然后从输入流中读取文件的字节流。根据输出的结果,可以看出,test 1是以UTF-8编码格式,将“中国”两个汉字的字节读入字节数组的
  • 【String utf8Str = new String(bytes, "gbk");】debug一下,看看utf8Str中存的字符数组是什么



    它想将字符以UTF-8编码格式获取的字节数组再以GBK编码的形式转化为字符。
    GBK是定长编码,UTF-8是不定长编码,这一转肯定是要出问题的。“中国”两个字符以UTF-8编码,是长度为6的字节数组,GBK字符字节长度为2,所以变成了三个字符,但是在JVM中,都是Unicode字符编码来表示字符的,所以JVM又将三个GBK字符编码转换成了Unicode编码,存在JVM内存中,才有了utf8Str上图中的情况。

对于test 2,

  • 【 inputStream = new FileInputStream(new File("demo.txt"));】建立字节输入流
  • 【 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "GBK");】InputStreamReader是字节流向字符流转换的桥梁,可以指定编码格式。
  • 【 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);】 BufferedReader是字符流的一种实现方式,后面会介绍。
  • 【String cs = bufferedReader.readLine();】按行读取文本。字符串cs中的字符数组存储的是什么呢?


    image.png

    这行代码在读取文本中的信息的时候,应该也是经历了如下步骤

  1. 获取UTF-8编码格式字节数组 bs
  2. 根据GBK编码,将bs转化为GBK字符
  3. 将GBK字符转化为其对应的Unicode编码,于是有了上图cs的情况。

从上面的两个test可以看出, test 1可以操作到字节级别,这个就叫做字节流,test 2操作最小的也是一个Unicode字符,这个叫做字符流。从我们创建字符流对象的过程,可以知道,字符流其实是对字节流的封装,只不过字符流一次会操作一个Unicode字符。
另外,字节流处理的范围更加大,例如图片、音频等,我们可以获取他们的字节流,但是它们有自己的编码规则,无法转化为我们的字符。

Java I/O编码系统

  • 面向字节流的InputStream和OutputStream
  • 面向字符流的Reader 和 Writer

字节流的InputStream和OutputStream是一切的基础,实际总线中流动的只有字节流。Java中负责从字节流向字符流解码的桥梁是:
InputStreamReader和OutputStreamWriter,可以指定以什么编码格式读取或写入。

Java中的字符流处理的最基本的单元是Unicode码元(大小2字节),它通常用来处理文本数据。所谓Unicode码元,也就是一个Unicode代码单元,范围是0x0000~0xFFFF。在以上范围内的每个数字都与一个字符相对应,Java中的String类型默认就把字符以Unicode规则编码而后存储在内存中。然而与存储在内存中不同,存储在磁盘上的数据通常有着各种各样的编码方式。使用不同的编码方式,相同的字符会有不同的二进制表示。实际上字符流是这样工作的:

  • 输出字符流:把要写入文件的字符序列(实际上是Unicode码元序列)转为指定编码方式下的字节序列(OutputStreamWriter指定的编码,如果没有指定,则按照操作系统默认),然后再写入到文件中;
  • 输入字符流:把要读取的字节序列按指定编码方式解码为相应字符序列(按照InputStreamReader指定的编码,先编码,再转码为Unicode码元序列)从而可以存在JVM内存中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容