Java 中的 I/O 小结

文章目录
  1. 1. 简介 I/O
  2. 2. 详谈 I/O
    1. 2.1. InputStream
    2. 2.2. OutputStream
    3. 2.3. Reader
    4. 2.4. Writer
  3. 3. 总结
  4. 4. 参考文献

虽有嘉肴,弗食,不知其旨也;虽有至道,弗学,不知其善也。是故学然后知不足,教然后知困。知不足,然后能自反也;知困,然后能自强也。

Java 中的 I/O 操作主要指使用 Java 进行输入和输出的操作。Java 的 I/O 机制是基于数据流进行输入和输出的,数据流即表示字符或者字节数据的流动序列。初学的时候感觉繁杂,难以摸清规律,而今,对 Java 中的 I/O 作一简单小结。

简介 I/O

数据流即一串连续不断的数据的集合,如同水管里的水流一样,一端一点点地供水,而另一端可以看到源源不断的水流。

数据写入程序时,可以一段段地向数据流管道中写入数据,这些数据会按着先后顺序,形成一个长的数据流。

对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中任意长度的数据,但是,只能先读取前面的数据,再读取后面的数据 (不能随机读取)。

此外,注意,无论写入时是将数据分多次写入,还是作为一个整体一次性写入,读取时的效果是完全一样的。

数据流分类:

流序列中的数据既可以是未经加工的原始二进制数据,也可以是经过特定编码处理后,符合某种格式规定的特定数据。

  • 字节流:数据流中最小的数据单元是字节
  • 字符流:数据流中最小的数据单元是字符

Java 中,字符是 Unicode 编码,一个字符占用两个字节。

java.io 包中,最重要的即 5 个类和 1 个接口。

  • 5 个类:OutputStream、InputStream、Writer、Reader 和 File
  • 1 个接口:Serializable

分为以下 3 个层次:

  • 最主要的流式:OutputStream、InputStream、Writer 和 Reader
  • 非流式:比如 File 类、RandomAccessFile 类和 FileDescriptor 类
  • 文件读取部分,及与安全相关的类:比如 SerializablePermission 类

如下所示:

详谈 I/O

如下图:

按照来源/去向分类为:

  • File:FileInputStream, FileOutputStream, FileReader, FileWriter
  • byte[]: ByteArrayInputStream, ByteArrayOutputStream
  • Char[]: CharArrayReader, CharArrayWriter
  • String: StringBufferInputStream, StringReader, StringWriter
  • 网络数据流:InputStream, OutputStream, Reader, Writer

InputStream

输入流,为字节流,二进制格式。抽象类,基于字节的输入操作,是所有输入流的父类,依靠其子类实现各种功能。

上图几种不同的 InputStream:

  • FileInputStream:从文件中读取内容,把一个文件作为 InputStream
  • FilterInputStream:抽象类,作为所谓“装饰器”的接口
  • PipedInputStream:实现了管道化的概念,在线程中使用
  • SequenceInputStream:将多个 InputStream 顺序连接起来
  • StringBufferInputStream:将一个 String 对象作为 InputStream,已废弃
  • ByteArrayInputStream:将内存中的一个缓冲区作为 InputStream 使用

常用方法如下:

  • public abstract int read():读取一个字节的数据,返回值是高位补 0 的 int 类型值,若返回 -1,则说明未读取到任何字节,读取工作结束
  • public int read(byte b[]):读取 b.length 个字节的数据,放入到 b 数组中,返回值即是读取的字节数
  • public int read(byte b[], int off, int len):从输入流中最多读取 len 个字节的数据,存放到偏移量为 off 的 b 数组中
  • public int available():返回输入流中可以读取的字节数。注意,若输入阻塞,当前所在的线程会被挂起;若 InputStream 对象调用该方法,只会返回 0。该方法必须由继承 InputStream 类的子类对象调用才有用
  • public void close():完成后,需要关闭打开的流

OutputStream

输出流,为字节流,二进制格式。抽象类,基于字节的输出操作,是所有输出流的父类,依靠其子类实现各种功能。

上图几种不同的 OutputStream:

  • FileOutputStream:将数据写入到文件中
  • FilterOutputStream:抽象类,作为装饰器的接口
  • PipedOutputStream:所有写到其中的内容,会自动作为 “PipedInputStream” 的输出
  • ByteArrayOutputStream:在内存中创建一个缓冲区,所有输出到“流”的内容都放置在此区域

常用方法如下:

  • public abstract void write(int b):先将 int 转换为 byte 类型,把低字节写入到输出流中
  • public void write(byte b[]):将参数 b 中的字节写到输出流中
  • public void write(byte b[], int off, int len):将参数 b 从偏移量 off 开始的 len 个字节写到输出流中
  • public void flush():将数据缓冲区中的数据全部输出,并清空缓冲区
  • public void close():关闭输出流,并释放与流相关的系统资源

Reader

与 InputStream 类似,只是 Reader 是针对字符的。

注意两个:

  • InputStreamReader:从输入流中读取字节,再将它们转换成字符
  • BufferedReader:Reader 对象作为参数,对其添加字符缓冲器,使用 readline() 读取一行

Writer

与 OutputStream 类似,针对字符,多了 append 操作,也是针对字符的。

总结

如何选择合适的 I/O 流,步骤依次为:

  • 确定输入还是输出

    :InputStream, Reader

    :OutputStream, Writer

  • 确定操作的数据对象是否为纯文本

    是的:字符流,Reader, Writer

    不是:字节流,InputStream, OutputStream

  • 确定具体细节

    比如文件

    读:FileInputStream, FileReader

    写:FileOutputStream, FileWriter

  • 确定是否需要转换流

    需要的话,使用转换流,如 InputStreamReader, OutputStreamWriter

  • 确定是否需要缓冲提高效率

    需要的话,如 BufferedInputStream, BufferedReader 等

  • 确定是否需要格式化输出

至此,关于 Java 中的 I/O 简单小结完毕。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.https://docs.oracle.com/javase/8/docs/api/java/io/package-summary.html

2.https://docs.oracle.com/javase/tutorial/essential/io/