在
JDK 1.4
以前,
Java
的
IO
操作集中在
java.io
这个包中,是基于流的阻塞(
blocking
)
API
。对于大多数应用来说,这样的
API
使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用,
往往需要一个更为有效的方式来处理
IO
。从
JDK 1.4
起,
NIO
API
作为一个基于缓冲区,并能
提供非阻塞
(non-blocking)IO
操作的
API
被引入。本文对其进行深入的介绍。
NIO API
主要集中在
java.nio
和它的
subpackages
中:
java.nio
定义了
Buffer
及其数据类型相关的子类。其中被
java.nio.channels
中的类用来进行
IO
操作的
ByteBuffer
的作用非常重要。
java.nio.channels
定义了一系列处理
IO
的
Channel
接口以及这些接口在文件系统和网络通讯上的实现。通过
Selector
这个类,还提供了进行非阻塞
IO
操作的办法。这个包可以说是
NIO API
的核心。
java.nio.channels.spi
定义了可用来实现
channel
和
selector API
的抽象类。
java.nio.charset
定义了处理字符编码和解码的类。
java.nio.charset.spi
定义了可用来实现
charset API
的抽象类。
java.nio.channels.spi
和
java.nio.charset.spi
这
两个包主要被用来对现有
NIO API
进行扩展,在实际的使用中,我们一般只和另外的
3
个包打交道。下面将对这
3
个包一一介绍。
Package java.nio
这个包主要定义了
Buffer
及其子类。
Buffer
定义了一个线性存放
primitive
type
数据的容器接口。对于除
boolean
以外的其他
primitive type
,都有一个相
应的
Buffer
子
类,
ByteBuffer
是其中最重要的一个子类。
下面这张
UML
类图描述了
java.nio
中的类的关系:
Buffer
定义了一个可以线性存放
primitive
type
数据的容器接口。
Buffer
主要包含了与类型(
byte, char…
)无关的功能。值得
注意的是
Buffer
及其子类都不是线程安全的。
每个
Buffer
都有以下的属性:
capacity
这个
Buffer
最多能放多少数据。
capacity
一般在
buffer
被创建的时候指定。
limit
在
Buffer
上进行的读写操作都不能越过这个下标。当写数据到
buffer
中时,
limit
一般和
capacity
相等,当读数据时,
limit
代表
buffer
中有效数据的长度。
position
读
/
写操作的当前下标。当使用
buffer
的相对位置进行读
/
写操作时,读
/
写会从这个下标进行,并在操作完成后,
buffer
会更新下标的值。
mark
一个临时存放的位置下标。调用
mark()
会将
mark
设为当前的
position
的值,以后调用
reset()
会将
position
属性设置为
mark
的值。
mark
的值总是小于等于
position
的值,如果将
position
的值设的比
mark
小,当前的
mark
值会被抛弃掉。
这些属性总是满足以下条件:
0 <= mark
<= position
<= limit
<= capacity
limit
和
position
的值除了通过
limit()
和
position()
函数来设置,也可以通
过下面这些函数来改变:
Buffer clear()
把
position
设为
0
,把
limit
设为
capacity
,一般在把数据写入
Buffer
前调用。
Buffer flip()
把
limit
设为当前
position
,把
position
设为
0
,一般在从
Buffer
读出数据前调用。
Buffer rewind()
把
position
设为
0
,
limit
不变,一般在把数据重写入
Buffer
前调用。
Buffer
对象有可能是只读的,这时,任何
对该对象的写操作都会触发一个
ReadOnlyBufferException
。
isReadOnly()
方法可以用来判断一个
Buffer
是否只读。
ByteBuffer
在
Buffer
的子类中,
ByteBuffer
是一个地位较为特殊的类,因为在
java.io.channels
中定义的各种
channel
的
IO
操作基本上都是围绕
ByteBuffer
展开的。
ByteBuffer
定义了
4
个
static
方法来做创建工作:
ByteBuffer allocate(int capacity)
创建一个指定
capacity
的
ByteBuffer
。
ByteBuffer allocateDirect(int capacity)
创建一个
direct
的
ByteBuffer
,这样的
ByteBuffer
在参与
IO
操作时性能会更好(很有可能是在底层的实现使用了
DMA
技术),相应的,创建和回收
direct
的
ByteBuffer
的代价也会高一些。
isDirect()
方法可以检查一个
buffer
是否是
direct
的。
ByteBuffer wrap(byte [] array)
ByteBuffer wrap(byte [] array, int offset, int length)
把一个
byte
数组或
byte
数组的一部分包装成
ByteBuffer
。
ByteBuffer
定义了一系列
get
和
put
操作来从中读写
byte
数据,如下面几个:
byte get()
ByteBuffer get(byte [] dst)
byte get(int index)
ByteBuffer put(byte b)
ByteBuffer put(byte [] src)
ByteBuffer put(int index, byte b)
这些操作可分为绝对定位和相对定为两种,相对定位的读写操作依靠
position
来定位
Buffer
中的位置,并在操作完成后会更
新
position
的
值。
在其它类型的
buffer
中,也定义了相同的函数来读写数据,唯一不同的就是一些参数和返回值的类型。
除了读写
byte
类型数据的函数,
ByteBuffer
的一个特别之处是它还定义了读写其它
primitive
数据的方法,如:
int getInt()
从
ByteBuffer
中读出一个
int
值。
ByteBuffer putInt(int value)
写入一个
int
值到
ByteBuffer
中。
读写其它类型的数据牵涉到字节序问题,
ByteBuffer
会按其字节序(大字节序或小字节序)写入或读出一个其它类型的数据(
int,long…
)。字节序可以用
order
方法来取得和设置:
ByteOrder order()
返回
ByteBuffer
的字节序。
ByteBuffer order(ByteOrder bo)
设置
ByteBuffer
的字节序。
ByteBuffer
另一个特别的地方是可以
在它的基础上得到其它类型的
buffer
。如:
CharBuffer asCharBuffer()
为当前的
ByteBuffer
创建一个
CharBuffer
的视图。在该视图
buffer
中的读写操作会按照
ByteBuffer
的字节序作用到
ByteBuffer
中的数据上。
用这类方法创建出来的
buffer
会从
ByteBuffer
的
position
位置开始到
limit
位置结束,可以看作是这段数据的视图。视图
buffer
的
readOnly
属性和
direct
属性与
ByteBuffer
的一致,而且也只有通过这种方法,才可以得到其他数据类型的
direct buffer
。
ByteOrder
用来表示
ByteBuffer
字节序的类,可将其看成
java
中的
enum
类型。主要定义了下面几个
static
方法和属性:
ByteOrder BIG_ENDIAN
代表大字节序的
ByteOrder
。
ByteOrder LITTLE_ENDIAN
代表小字节序的
ByteOrder
。
ByteOrder nativeOrder()
返回当前硬件平台的字节序。
MappedByteBuffer
ByteBuffer
的子类,是文件内容在内
存中的映射。这个类的实例需要通过
FileChannel
的
map()
方法来创建。
接下来看看一个使用
ByteBuffer
的例子,这个例子从标准输入不停地读入字符,当读满一行后,将收集的字符写到标准输出:
public
static
void
main(String
[]
args)
throws
IOException
{
//
创建一个
capacity
为
256
的
ByteBuffer
ByteBuffer
buf
=
ByteBuffer.allocate(256);
while
(
true
)
{
//
从标准输入流读入一个字符
int
c
=
System.in.read();
//
当读到输入流结束时,退出循环
if
(c
==
-1)
break
;
//
把读入的字符写入
ByteBuffer
中
buf.put((
byte
)
c);
//
当读完一行时,输出收集的字符
if
(c
==
'\n'
)
{
//
调用
flip()
使
limit
变为当前的
position
的值
,position
变为
0,
//
为接下来从
ByteBuffer
读取做准备
buf.flip();
//
构建一个
byte
数组
byte
[]
content
=
new
byte
[buf.limit()];
//
从
ByteBuffer
中读取数据到
byte
数组中
buf.get(content);
//
把
byte
数组的内容写到标准输出
System.out.print(
new
String(content));
//
调用
clear()
使
position
变为
0,limit
变为
capacity
的值,
//
为接下来写入数据到
ByteBuffer
中做准备
buf.clear();
}
}
}
|
Package
java.nio.channels
这个包定义了
Channel
的概念,
Channel
表现了一个可以进行
IO
操作的通道(比如,通过
FileChannel
,我们可以对文件进行读写操作)。
java.nio.channels
包含了文件系统和网络通讯相关的
channel
类。这个包通过
Selector
和
SelectableChannel
这两个类,还定义了一个进行非阻塞(
non-blocking
)
IO
操作的
API
,这对需要高性能
IO
的应用非常重要。
下面这张
UML
类图描述了
java.nio.channels
中
interface
的关系:
Channel
Channel
表现了一个可以进行
IO
操作的通道,该
interface
定义了以下方法:
boolean isOpen()
该
Channel
是否是打开的。
void close()
关闭这个
Channel
,相关的资源会被释放。
ReadableByteChannel
定义了一个可从中读取
byte
数据的
channel interface
。
int read(ByteBuffer dst)
从
channel
中读取
byte
数据并写到
ByteBuffer
中。返回读取的
byte
数。
WritableByteChannel
定义了一个可向其写
byte
数据的
channel interface
。
int write(ByteBuffer src)
从
ByteBuffer
中读取
byte
数据并写到
channel
中。返回写出的
byte
数。
ByteChannel
ByteChannel
并没有定义新的方法,
它的作用只是把
ReadableByteChannel
和
WritableByteChannel
合并在一起。
ScatteringByteChannel
继承了
ReadableByteChannel
并提供了同时往几个
ByteBuffer
中写数据的能力。
GatheringByteChannel
继承了
WritableByteChannel
并提供了同时从几个
ByteBuffer
中读数据的能力。
InterruptibleChannel
用来表现一个可以被异步关闭的
Channel
。这表现在两方面:
1.
当一个
InterruptibleChannel
的
close()
方法被调用时,其它
block
在这个
InterruptibleChannel
的
IO
操作上的线程会接收到一个
AsynchronousCloseException
。
2.
当一个
线程
block
在
InterruptibleChannel
的
IO
操作上时,另一个线程调用该线程的
interrupt()
方法会导致
channel
被关闭,该线程收到一个
ClosedByInterruptException
,同时线程的
interrupt
状态会被设置。
接下来的这张
UML
类图描述了
java.nio.channels
中类的关系:
非阻塞
IO
非阻塞
IO
的支持可以算是
NIO API
中最重要的功能,非阻塞
IO
允许应用程序同时监控多个
channel
以提高性能,这一功能是通过
Selector
,
SelectableChannel
和
SelectionKey
这
3
个类来实现的。
SelectableChannel
代表了可
以支持非阻塞
IO
操
作的
channel
,
可以将其注册在
Selector
上,这种注册的关系由
SelectionKey
这个类来表现(见
UML
图)。
Selector
这个类通过
select()
函数,给应用程序提供了一个可以同时监控多个
IO
channel
的方法:
应用程序通过调用
select()
函数,让
Selector
监控注册在其上的多个
SelectableChannel
,当有
channel
的
IO
操作可以进行时,
select()
方法就会返回以让应用程序检查
channel
的状态,并作相应的处理。
下面是
JDK 1.4
中非阻塞
IO
的一个例子,这段
code
使用了非阻塞
IO
实现了一个
time server
:
private
static
void
acceptConnections(
int
port)
throws
Exception
{
//
打开一个
Selector
Selector
acceptSelector
=
SelectorProvider.provider().openSelector();
//
创建一个
ServerSocketChannel
,这是一个
SelectableChannel
的子类
ServerSocketChannel
ssc
=
ServerSocketChannel.open();
//
将其设为
non-blocking
状态,这样才能进行非阻塞
IO
操作
ssc.configureBlocking(
false
);
margin: 0cm 0cm 0pt; text-align: le
分享到:
Global site tag (gtag.js) - Google Analytics
|
相关推荐
Java NIO(New Input/Output)API是在JDK 1.4版本中引入的一个重要的改进,它是对传统Java IO API的补充,旨在提供更高效、更灵活的数据输入和输出方式,特别是对于高并发和高性能的应用场景,如服务器端程序。NIO的...
下面是一些使用Java NIO的关键API: - `Selector.open()`:创建一个选择器实例。 - `Channel`接口及其子类,如`FileChannel`、`SocketChannel`等。 - `Buffer`接口及其子类,如`ByteBuffer`、`CharBuffer`等。 - `...
### Java NIO API详解 #### 一、引言 在Java早期版本中,I/O操作主要依赖于`java.io`包中的流式API,这些API虽然简单易用,但其本质是阻塞式的,这意味着每次读写操作都会等待直至完成。这种机制在处理大量并发...
根据给定文件的信息,我们可以详细地探讨NIO技术在锅炉模型中的应用,特别是与锅炉效率相关的几个关键指标及其计算方法。 ### 锅炉效率计算 #### 1. 过量空气系数与排烟氧量 - **定义**:过量空气系数是实际供给...
### Java NIO_API详解:构建高性能I/O操作的基石 #### 概述 在Java的早期版本中,I/O操作主要依赖于`java.io`包提供的流式、同步的API,这种模型对于多数应用场景而言已经足够高效且易于使用。然而,随着对性能...
### Java NIO 处理超大数据文件的知识点详解 #### 一、Java NIO简介 Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本...
Java NIO(New Input/Output)API是在JDK 1.4版本中引入的一个重要的功能扩展,它提供了与传统IO(基于流的IO)不同的I/O操作方式,特别是在处理高并发、高性能的服务端应用程序中,NIO具有显著的优势。传统的IO基于...
### Java NIO 系列教程知识点详解 #### Java NIO 概述 Java NIO (New IO) 是从 Java 1.4 开始提供的一种新的 I/O 处理方式,旨在改进传统 Java IO API 的性能并引入更高效的数据处理机制。Java NIO 主要包括三大...
### Java NIO 原理与使用详解 #### 一、Java NIO 概述 在深入了解 Java NIO 的工作原理及其使用之前,我们首先来了解一下什么是 Java NIO(New I/O)。Java NIO 是 Java SE 1.4 版本引入的一个全新的 I/O API,...
Java NIO实战之聊天室功能详解 Java NIO实战之聊天室功能详解主要介绍了Java NIO实战之聊天室功能,结合实例形式详细分析了Java NIO聊天室具体的服务端、客户端相关实现方法与操作注意事项。 Java NIO概述 Java ...
### Java-NIO2教程知识点详解 #### I/O发展简史 - **JDK1.0-1.3**: 在此期间,Java的I/O模型主要依赖于传统的阻塞I/O方式,这种模式下,应用程序在等待I/O操作完成时无法执行其他任务,导致效率低下。此外,当时的...
### Java NIO 教程知识点详解 #### 一、Java NIO 概述 Java NIO(New IO),从 Java 1.4 开始引入,是 Java 标准 IO API 的一个补充,提供了与标准 IO 不同的工作方式。Java NIO 的主要特性包括: 1. **基于通道...
### Java NIO 核心概念详解 #### 一、Java NIO 基本介绍 Java NIO(New IO 或 NonBlocking IO)是 Java 1.4 版本开始引入的一种全新的 I/O API,旨在提高 I/O 吞吐量。与传统的阻塞 I/O 相比,NIO 的设计思想更为...
Java 2还包括丰富的API,如Swing库用于构建图形用户界面(GUI),I/O和NIO(非阻塞I/O)库用于高效的数据传输,以及XML处理API等。这些高级主题会帮助开发者构建功能丰富的应用程序。 最后,本书可能还会涉及Java的...
- **java.nio**:非阻塞I/O,提供缓冲区、通道和选择器,性能优于传统的`java.io`。 3. **类和接口详解** - `ArrayList`与`LinkedList`:两种常见的列表实现,各有优缺点,适用于不同的场景。 - `HashMap`与`...
Java NIO 概述与实现详解 Java NIO(New IO 或 Non Blocking IO)是从 Java 1.4 版本开始引入的一个新的IO API,可以替代标准的 Java IO API。NIO 支持面向缓冲区的、基于通道的 IO 操作。NIO 将以更加高效的方式...