码迷,mamicode.com
首页 > 编程语言 > 详细

Java 中的 I/O 抽象

时间:2019-04-05 16:50:29      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:file   cells   文件的   返回值   将不   new   amp   bool   统一   

Table of Contents

  1. 前言
  2. 字节流
    1. 常用实现
  3. 字符流
    1. 常用实现
  4. 缓冲区
  5. 各种字节流
  6. 结语

前言

由于在接触 Java 之前使用的语言是 Python,所以在转到 Java 后对 Java 的 I/O 操作各种不习惯。

研究后发现 Java 的 I/O 模型和 Python 的基本上还是一样的,只是在接口的设计上有些区别,主要是为了符合 OOP 的思想吧。

这篇博客的主要内容便是和 Java I/O 相关的总结。

字节流

和 Python 一样,Java 中最底层的 I/O 接口处理的是 字节序列, 但是和 Python 中的文件对象一把梭不一样,Java 将输入和输出分别抽象为了两个对象。

处理输入流的 InputStream 和处理输出流的 OutputStream.

这两个类都是抽象类,因此具体的和输入输出相关的功能将由它们的子类实现,而它们则提供一些基本的接口:

  • InputStream 提供的部分接口:

    方法 作用
    abstract int read() 读取一个字节,碰到输入流结尾时返回 -1
    int read(byte[] b) 将数据读入提供的字节数组,并返回实际读入的字节数,或者在碰到输入流结尾时返回 -1
    int read(byte[] b, int off, int len) 将数据读入提供的字节数组,并返回实际读入的字节数,或者在碰到输入流结尾时返回 -1,写入的范围由 off 和 len 指定
  • OutputStream 提供的部分接口:

    方法 作用
    abstract void write() 写入一个字节的数据
    void write(byte[] b) 写入一个字节数组的数据
    void write(byte[] b, int off, int len) 写入字节数组的数据,数据范围由 off 和 len 指定
    void flush() 将缓存的数据全部写入目标

可以看到,抽象方法其实只有 read()write(), 其他的方法会调用这两个方法,因此子类只需要提供这两个抽象方法的实现就可以了。

常用实现

Java 中字节流的具体实现很多,但最常用的应该就是和 文件 相关的了,因此在这里将它们列举出来:

  • FileInputStream 的构造方法:

    构造方法 说明
    FileInputStream(FileDescriptor fdObj) 根据指定的文件描述符创建输入流
    FileInputStream(File file) 根据指定的文件对象创建输入流
    FileInputStream(String name) 根据指定的文件名称创建输入流
  • FileOutputStream 的构造方法和 FileInputStream 的基本相同,不同的是多了两个存在布尔标志的构造方法:

    构造方法 说明
    FileOutputStream(File file, boolean append) 根据指定的文件对象创建输出流,布尔标志指定是否追加
    FileOutputStream(String name, boolean append) 根据指定的文件名称创建输出流,布尔标志指定是否追加

在之前学习 C 和 Python 的过程中便了解到 文件描述符 是一个很有用的东西,通过它可以实现一些很有用的功能。

在 Java 中获取文件描述符可以通过调用 FileInputStreamFileOutputStream 对象的 getFD() 方法完成,而标准输入输出的文件描述符则需要通过 FileDescriptor 的静态字段获取。

字符流

通过字节流可以完成很多 I/O 操作,但是如果连文本文件的处理都通过字节流来完成的话就太麻烦了。因此,为了解决这样的问题,
字符流便诞生了。

字符流 是对 字节流 的一层封装,在 Java 中通过 ReaderWriter 这两个抽象类来表示。

和 InputStream 和 OutputStream 一样,具体的功能将由它们的子类实现,而它们则提供一些基本的接口,这里列举出最基本的接口:

  • Reader:

    方法 作用
    int read() 读取单个字符,返回值是该字符的码点,到达流的末尾就返回 -1
  • Writer:

    方法 作用
    void write(int c) 写入单个字符
    void write(String str) 写入字符串
    abstract void flush() 将缓存的数据全部写入目标

需要注意的是,这里的 read() 方法和 write() 都不是抽象方法了,因为这两个方法实际上都是调用内部的 字节流 完成工作,因此,只需要相应的字节流实现基本的功能就足够了。

常用实现

Java 字符流实现中最常用的应该是 InputStreamReaderOutputStreamWriter 了,它们的构造方法如下:

Reader 构造方法 Writer 构造方法 说明
InputStreamReader(InputStream in) OutputStreamWriter(OutputStream out) 根据默认编码创建字符流
InputStreamReader(InputStream in, Charset cs) OutputStreamWriter(OutputStream out, Charset cs) 根据指定字符集创建字符流
InputStreamReader(InputStream in, CharsetDecoder dec) OutputStreamWriter(OutputStream out, CharsetEncoder dec) 根据指定字符集解/编码器创建字符流
InputStreamReader(InputStream in, String charsetName) OutputStreamWriter(OutputStream out, String charsetName) 根据指定字符集名称创建字符流

同时,针对文件操作,Java 提供了这两个类的子类 FileReaderFileWriter, 使用这两个类可以省略手动创建字节流的过程,具体内容可以查看相关文档。

缓冲区

I/O 操作的一个常识:频繁的 I/O 操作的效率是很低的,所以我们加一个缓冲区吧!

Java 中我们可以通过 BufferedInputStreamBufferedOutputStream 为字节流添加缓冲区,通过 BufferedReaderBufferedWriter 为字符流添加缓冲区。

这样一来,一段经典的代码就成型了:

// 字节流 -> 字符流 -> 缓冲区
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("example.txt")));

很完美是不是!

各种字节流

虽然说最常用的字节流式文件字节流(大概),但是,输入输出的环境是复杂的,处理文件以外,其他的设备如内存、网络等都可能用到输入输出,
而且不同的条件下需要的功能还不一样。

字符流的需求相对来说较为统一,因此一般情况下 InputStreamReaderOutputStreamWriter 完全可以一统天下,但是对于 字节流 来说,Java 提供了各种各样的实现。

尤其是 FilterInputStreamFilterOutputStream 的子类,它们都有以输出/输出流作为参数的构造方法,因此,我们可以将不同的 Filter 组装起来,得到我们想要的功能。

这是除了 字节-字符-缓冲 以外让我觉得最 Beautiful 的设计,能够灵活的适应各种需求。

这些 Filter 的使用可以查看官方文档或者看看《Java 核心技术卷卷二》的 2.1.3 节,这是相当棒的功能。

结语

写完博客回头看,感觉质量有点差……

篇幅太少了,很多东西都没有说清楚,属于适合自己回顾的博客 @_@

另外,很想吐槽的是:作为面向对象的语言,Java 内置的网络库居然没有将 请求响应 这两个对象分开!!!

用起来各种不顺手……

Java 中的 I/O 抽象

标签:file   cells   文件的   返回值   将不   new   amp   bool   统一   

原文地址:https://www.cnblogs.com/rgbit/p/10659031.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!