java传统IO流-BIO

介绍

  数据都以二进制存储在设备中,流就是将这些数据以二进制在各种设备间进行传输。

  IO流的核心特点:

  1. 顺序读写:读写数据时,大部分情况下都是按照顺序读写,读取时从文件开头的第一个字节到最后一个字节,写出时也是也如此(RandomAccessFile 可以实现随机读写)。
  2. 读写数据时本质上都是对字节数组做读取和写出操作,即使是字符流,也是在字节流基础上转化为一个个字符,所以字节数组是 IO 流读写数据的本质。

分类

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

  • 输入流:从磁盘或者其它外设中将数据输入到进程中。
  • 输出流:从进程中将数据输出到磁盘或者其他外设中保存。

字符流&字节流

  根据处理数据的基本单位不同分为:字节流和字符流。

  • 字节流:以字节(1Byte=8bit) 为单位做数据的传输。
  • 字符流:以字符为单位做数据的传输。

    字符流的本质也是通过字节流读取,Java 中的字符采用 Unicode 标准,在读取和输出的过程中,通过以字符为单位,查找对应的码表将字节转换为对应的字符。

  根据这两种分类,在java.io包中定义了四个顶层的抽象:

数据类型/数据流向字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

  在这四个顶层抽象下面还有很多的成员,分别有不同的作用。

io
IO

  java中处理传输用的外,还提供了一堆扩展的流,比如压缩,序列化用的。

IO

  这其中还提供了用于字节流与字符流中间的转换流。

转换流/数据类型转换
输入(字节->字符)InputStreamReader
输出(字符->字节)OutputStreamWriter

在存储设备上,所有数据都是以字节为单位存储的,所以输入到内存时必定是以字节为单位输入,输出到存储设备时必须是以字节为单位输出,字节流才是计算机最根本的存储方式,而字符流是在字节流的基础上对数据进行转换,输出字符,但每个字符依旧是以字节为单位存储的。

节点流和处理流

  这是对流的根据功能的再一次分类。

  • 节点流:节点流是真正传输数据的流对象,用于向特定的一个地方(节点)读写数据,称为节点流。
  • 处理流:处理流是对节点流的封装,使用外层的处理流读写数据,本质上是利用节点流的功能,外层的处理流可以提供额外的功能。处理流的基类都是以Filter开头。

  还有将两个流合并的SequenceInputOutStream。


字节流和字符流的转换

  从任何地方把数据读入到内存都是先以字节流形式读取,即使是使用字符流去读取数据,依然成立,因为数据永远是以字节的形式存在于互联网和硬件设备中,字符流是通过字符集的映射,才能够将字节转换为字符。

  java中提供了两种转换流:

  • InputStreamReader:从字节流转换为字符流,将字节数据转换为字符数据读入到内存。
  • OutputStreamWriter:从字符流转换为字节流,将字符数据转换为字节数据写出到指定位置。
  1. 传统的 BIO 是以流为基本单位处理数据的,想象成水流,一点点地传输字节数据,IO 流传输的过程永远是以字节形式传输。
  2. 字节流和字符流的区别在于操作的数据单位不相同,字符流是通过将字节数据通过字符集映射成对应的字符,字符流本质上也是字节流。

整理

  所有的流基本如下:

数据类型基于字节的Input基于字节的Output基于字符的Input基于字符的Output
基础InputStreamOutputStreamReaderWriter
转换InputStreamReaderOutputStreamWriter
数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
文件FileInputStream、RandomAccessFileFileOutputStream、RandomAccessFileFileReaderFileWriter
管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
缓冲BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
过滤FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
解析PushbackInputStream、StreamTokenizerPushbackReader、LineNumberReader
字符串StringReaderStringWriter
数据DataInputStreamDataOutputStream
数据格式化PrintStreamPrintWriter
对象ObjectInputStreamObjectOutputStream
合并流SequenceInputStream

传统BIO的问题

  1. 每个请求都需要创建独立的线程,与对应的客户端进行数据处理。
  2. 当并发数大时,需要创建大量线程来处理连接,系统资源占用较大。
  3. 连接建立后,如果当前线程暂时没有数据可读,则当前线程会一直阻塞在Read操作上,造成线程资源浪费。

参考文献 & 鸣谢

JAVA IO BIO NIO AIO