目 录
1. Core Java
1.1 NIO学习系列:核心概念及基本读写 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 NIO学习系列:缓冲区内部实现机制 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 NIO学习系列:连网和异步IO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4 NIO学习系列:缓冲区更多特性及分散/聚集IO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.5 NIO学习系列:文件锁定和字符集 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
http://zhangshixi.javaeye.com
第 2 / 32 页
1.1 NIO学习系列:核心概念及基本读写
发表时间: 2010-05-31
1. 引言
I/O流或者输入/输出流指的是计算机与外部世界或者一个程序与计算机的其余部分的之间的接口。新的输入/
输出(NIO)库是在JDK 1.4中引入的。NIO弥补了原来的I/O的不足,它在标准Java代码中提供了高速的、面向块
的I/O。
原来的I/O库与NIO最重要的区别是数据打包和传输的方式的不同,原来的 I/O 以流 的方式处理数据,而
NIO 以块 的方式处理数据。
面向流的I/O系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数
据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,
这样也是相对简单的。不利的一面是,面向流的I/O通常相当慢。
NIO与原来的I/O有同样的作用和目的,但是它使用块I/O的处理方式。每一个操作都在一步中产生或者消费一
个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的I/O缺少一些面向流的I/O所具有的
优雅性和简单性。
2. 从一个例子开始
下面我们从一个简单的使用IO和NIO读取一个文件中的内容为例,来进入NIO的学习之旅。
使用IO来读取指定文件中的前1024字节并打印出来:
/**
* 使用IO读取指定文件的前1024个字节的内容。
* @param file 指定文件名称。
* @throws java.io.IOException IO异常。
*/
public void ioRead(String file) throws IOException {
FileInputStream in = new FileInputStream(file);
byte[] b = new byte[1024];
in.read(b);
System.out.println(new String(b));
}
/**
* 使用NIO读取指定文件的前1024个字节的内容。
* @param file 指定文件名称。
http://zhangshixi.javaeye.com
1.1 NIO学习系列:核心概念及基本读写
第 3 / 32 页
* @throws java.io.IOException IO异常。
*/
public void nioRead(String file) throws IOException {
FileInputStream in = new FileInputStream(file);
FileChannel channel = in.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
byte[] b = buffer.array();
System.out.println(new String(b));
}
从上面的例子中可以看出,NIO以通道Channel和缓冲区Buffer为基础来实现面向块的IO数据处理。下面将讨
论并学习NIO 库的核心概念以及从高级的特性到底层编程细节的几乎所有方面。
3. 核心概念:通道和缓冲区
1) 概述:
通道和缓冲区是NIO中的核心对象,几乎在每一个I/O操作中都要使用它们。
通道Channel是对原I/O包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个Channel
对象。
缓冲区Buffer实质上是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道
中读取的任何数据都要读到缓冲区中。
2) 缓冲区:
Buffer是一个容器对象,它包含一些要写入或者刚读出的数据。在NIO中加入Buffer对象,体现了新库与原I/
O的一个重要区别。在面向流的I/O中,您将数据直接写入或者将数据直接读到Stream对象中。
在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是
写入到缓冲区中的。任何时候访问NIO中的数据,您都是将它放到缓冲区中。
缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不仅仅
是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
最常用的缓冲区类型是ByteBuffer。 一个ByteBuffer可以在其底层字节数组上进行get/set操作(即字节的获取
和设置)。
ByteBuffer不是NIO中唯一的缓冲区类型。事实上,对于每一种基本Java类型都有一种缓冲区类型:
ByteBuffer
CharBuffer
ShortBuffer
http://zhangshixi.javaeye.com
1.1 NIO学习系列:核心概念及基本读写
第 4 / 32 页
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
每一个Buffer类都是Buffer接口的一个实例。 除了ByteBuffer, 每一个Buffer类都有完全一样的操作,只是
它们所处理的数据类型不一样。因为大多数标准I/O操作都使用ByteBuffer,所以它具有所有共享的缓冲区操作
以及一些特有的操作。
下面的UseFloatBuffer列举了使用类型化的缓冲区FloatBuffer的一个应用例子:
/**
* 使用 float 缓冲区。
* @version 1.00 2010-5-19, 10:30:59
* @since 1.5
* @author ZhangShixi
*/
public class UseFloatBuffer {
public static void main(String[] args) {
// 分配一个容量为10的新的 float 缓冲区
FloatBuffer buffer = FloatBuffer.allocate(10);
for (int i = 0; i < buffer.capacity(); i++) {
float f = (float) Math.sin((((float) i) / 10) * (2 * Math.PI));
buffer.put(f);
}
// 反转此缓冲区
buffer.flip();
// 告知在当前位置和限制之间是否有元素
while (buffer.hasRemaining()) {
float f = buffer.get();
System.out.println(f);
}
}
}
http://zhangshixi.javaeye.com
1.1 NIO学习系列:核心概念及基本读写
第 5 / 32 页
评论0