操作系统要移动的是大块数据(缓冲区), 这往往是在硬件直接存储器存取 (DMA) 的协助下完成的.
例如硬盘操作, 磁盘控制器通过 DMA 直接将数据写入内核的内存缓冲区. 一旦磁盘控制器完成了缓存的填写, 内核从内核空间的临时缓存拷贝数据到用户控件缓存中.
所以操作系统是以卡车的形式拷贝数据, 但是 Java 基于流的 I/O 模型, 是一铲子一铲子的加工数据.
面向流I/O的系统: 一次处理一个字节的数据. 一个输入流每次会读入一个字节的数据,一个输出流同样每次次消费一个字节的数据. 例如 Java 中的 SocketInputStream
和 FileInputStream
都是一次读取一个.
虽然你读取的数据时, 可能会使用如下代码:
byte[] receiveBuffer = new byte[128]; String clientMessage = ""; if((receiveBytes=in.read(receiveBuffer))!=-1) {
这里虽然指定了读取数据的大小, 但是要注意, 在读取时, 并不是一次性全部读取完成, 而是一个一个进行读取, 读取的次数就是数组的大小.
面向块I/O的系统: 以块为单位处理数据. 每个操作步骤会生成或消费一个块的数据.
先创建一个缓冲区
// 缓冲区的大小 private final static int BUFFER_SIZE = 1024; // 缓冲区 private ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
然后使用类似以下代码来读取数据到缓冲区.
int len = 0; while ((len = socketChannel.read(buffer)) > 0) {
也就是说, 直接读取缓冲区大小的一块数据, 保存到缓冲区中.
值得注意的是: 虽然创建缓冲区, 和上面创建的 byte[]
数组作用是一样的, 都是用来存储数据. 但是千万不要搞混了, 流 IO 和 块 IO 的底层处理方式不一样的.