三、IO

139 阅读4分钟

Java库的IO分为输入/输出两部分。

早期的Java 1.0版本的输入系统是InputStream及其子类,输出系统是OutputStream及其子类。

后来的Java 1.1版本对IO系统进行了重新设计。输入系统是Reader及其子类,输出系统是Writer及其子类。

Java1.1之所以要重新设计,主要是为了添加国际化支持(即添加了对16位Unicode码的支持)。具体表现为Java 1.0的IO系统是字节流,而Java 1.1的IO系统是字符流。

image.png

根据数据的流向分为:输入流和输出流。

  • 输入流 :把数据从 其他设备 上读取到 内存 中的流。
  • 输出流 :把数据从 内存 中写出到 其他设备 上的流。

根据数据的类型分为:字节流和字符流。

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。

在java中,字节是占1个Byte,即8位;而字符是占2个Byte,即16位。而且,需要注意的是,java的字节是有符号类型,而字符是无符号类型

一、字节流 & 字符流

字节流的抽象基类:

  InputStream,OutputStream

字符流的抽象基类:

  Reader,Writer

由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀,如InputStream的子类FileInputStream,Reader的子类FileReader。

二、为什么 I/O 流操作要分为字节流操作和字符流操作呢?

(1)字符流是由 Java 虚拟机将字节转换得到的,这个过程还算是比较耗时。

(2)如果我们不知道编码类型就很容易出现乱码问题。

因此,I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。

字节流在操作的时候,不会用到缓冲;而字符流会用到缓冲。所以,字符流的效率会更高一些。

为什么用到缓冲会效率更高一些呢?

因为缓冲本质上是一段内存区域,而文件大多是存储在硬盘或者Nand Flash上面。读写内存的速度比读写硬盘或Nand Flash上文件的速度快很多。

三、常用字符编码所占字节数?

字符流默认采用的是 Unicode 编码,我们可以通过构造方法自定义编码。

utf8 :英文占 1 字节,中文占 3 字节,

unicode:任何字符都占 2 个字节,

gbk:英文占 1 字节,中文占 2 字节。

四、常见的 IO 模型

UNIX 系统下, IO 模型一共有 5 种:

(1)同步阻塞 I/O

(2)同步非阻塞 I/O

(3)I/O 多路复用

(4)信号驱动 I/O

(5)异步 I/O

五、Java 中 3 种常见 IO 模型

(1)BIO 属于同步阻塞 IO 模型 。 同步阻塞 IO 模型中,应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。

(2)同步非阻塞 IO 模型 Java 中的 NIO 于 Java 1.4 中引入,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它是支持面向缓冲的,基于通道的 I/O 操作方法。 对于高负载、高并发的(网络)应用,应使用 NIO 。 Java 中的 NIO,有一个非常重要的选择器Selector的概念,也可以被称为多路复用器。通过它,只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后,才会为其服务。

(3)异步 IO 模型 AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。异步IO是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。 目前来说 AIO 的应用还不是很广泛。Netty 之前也尝试使用过 AIO,不过又放弃了。这是因为,Netty 使用了 AIO 之后,在 Linux 系统上的性能并没有多少提升。