彻底搞定NIO(一)
来源:互联网 发布:java 面试项目 编辑:程序博客网 时间:2024/06/05 19:35
因为小组要使用jetty和thrift等框架的原因,这些框架的很多设计思想实现都是基于NIO的,之前接触NIO都是懵懵懂懂的,所以这一次决心搞定NIO。
通道和缓冲区
概述
通道
和 缓冲区
是 NIO 中的核心对象,几乎在每一个 I/O 操作中都要使用它们。
通道是对原 I/O 包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象。一个 Buffer 实质上是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。
什么是缓冲区?
Buffer
是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer
对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream
对象中。
在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。
缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
缓冲区类型
最常用的缓冲区类型是 ByteBuffer
。一个 ByteBuffer
可以在其底层字节数组上进行 get/set 操作(即字节的获取和设置)。
ByteBuffer
不是 NIO 中唯一的缓冲区类型。事实上,对于每一种基本 Java 类型都有一种缓冲区类型:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
每一个 Buffer
类都是 Buffer
接口的一个实例。 除了 ByteBuffer
,每一个 Buffer 类都有完全一样的操作,只是它们所处理的数据类型不一样。因为大多数标准 I/O 操作都使用 ByteBuffer
,所以它具有所有共享的缓冲区操作以及一些特有的操作。
什么是通道?
Channel
是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。
正如前面提到的,所有数据都通过 Buffer
对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
通道类型
通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是 InputStream
或者 OutputStream
的子类), 而 通道
可以用于读、写或者同时用于读写。
因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在 UNIX 模型中,底层操作系统通道是双向的。
---------------------------理论到实践的华丽分割线-----------------------------------------------------------------
NIO 中的读和写
概述
读和写是 I/O 的基本过程。从一个通道中读取很简单:只需创建一个缓冲区,然后让通道将数据读到这个缓冲区中。写入也相当简单:创建一个缓冲区,用数据填充它,然后让通道用这些数据来执行写入操作。
从文件中读取
读取文件涉及三个步骤:(1) 从 FileInputStream
获取 Channel
FileInputStream fin = new FileInputStream( "readandshow.txt" );FileChannel fc = fin.getChannel();
(2) 创建 Buffer
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
(3) 将数据从 Channel
读到 Buffer
中。
fc.read( buffer );不需要告诉通道要读 多少数据 到缓冲区中。每一个缓冲区都有复杂的内部统计机制,它会跟踪已经读了多少数据以及还有多少空间可以容纳更多的数据。
写入文件
在 NIO 中写入文件类似于从文件中读取。首先从 FileOutputStream
获取一个通道:
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );FileChannel fc = fout.getChannel();
下一步是创建一个缓冲区并在其中放入一些数据 - 在这里,数据将从一个名为 message
的数组中取出,这个数组包含字符串 "Some bytes" 的 ASCII 字节(本教程后面将会解释 buffer.flip()
和 buffer.put()
调用)。
ByteBuffer buffer = ByteBuffer.allocate( 1024 );for (int i=0; i<message.length; ++i) { buffer.put( message[i] );}buffer.flip();
最后一步是写入缓冲区中:
fc.write( buffer );
注意在这里同样不需要告诉通道要写入多数据。缓冲区的内部统计机制会跟踪它包含多少数据以及还有多少数据要写入。
读写结合
fcin.read( buffer );fcout.write( buffer );
第一行将数据从输入通道 fcin
中读入缓冲区,第二行将这些数据写到输出通道 fcout
。
检查状态
下一步是检查拷贝何时完成。当没有更多的数据时,拷贝就算完成,并且可以在 read()
方法返回 -1 是判断这一点,如下所示:
int r = fcin.read( buffer );if (r==-1) { break;}
重设缓冲区
最后,在从输入通道读入缓冲区之前,我们调用 clear()
方法。同样,在将缓冲区写入输出通道之前,我们调用 flip()
方法,如下所示:
buffer.clear();int r = fcin.read( buffer );if (r==-1) { break;}buffer.flip();fcout.write( buffer );
clear()
方法重设缓冲区,使它可以接受读入的数据。 flip()
方法让缓冲区可以将新读入的数据写入另一个通道。
- 彻底搞定NIO(一)
- 一分钟彻底搞定HTTP报文格式
- 彻底搞定java文件上传(转)
- 彻底搞定C语言指针(转)
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定c指针
- 彻底搞定c指针
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定c指针
- 彻底搞定C指针
- 彻底搞定C指针
- 彻底搞定char/wchar_t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- 彻底搞定C指针
- Tempter of the Bone HDU
- 异常收集者 一NoClassDefFoundError
- 树莓派WEB服务器(Boa)CGI编程入门
- 关于python构造函数
- c++ c 时间戳获取 秒级 微秒级 纳秒级别
- 彻底搞定NIO(一)
- fiddler,他和其他抓包软件有什么区别,如何使用fiddler进行抓包
- Tomcat
- vue+axios+springboot+redis 实现session 共享
- input回车事件
- 使用Travis进行持续集成
- 戴尔poweredge r730服务器配置以及安装系统
- 448. Find All Numbers Disappeared in an Array
- Java中的关键字和保留字