国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > Java之NIO(一)Channel和Buffer

Java之NIO(一)Channel和Buffer

来源:程序员人生   发布时间:2015-06-05 09:17:41 阅读次数:3693次

java NIO 就是NEW I O,他与传统IO的最大的区分是 它是非阻塞IO。

Java NIO和IO之间的主要差别:


IO                NIO

面向流            面向缓冲

阻塞IO            非阻塞IO

无                 选择器

他们各自适用于不同的环境,这里只简单的说明其区分,具体的见博客:

http://ifeve.com/java-nio-vs-io/

NIO的核心api 是 Channel、Buffer和Selector,本品文章侧重介绍前两种。

1个简单例子

首先举1个简单的例子进行说明,这个例子使用NIO的api向1个文件中写入数据,然后把他读出来打印,此例子的注释很详细,可细细品味,另外有关NIO的概述可见译文:

http://ifeve.com/channels/

/** * NIO 简单测试例子,向1个文件中写入数据,然后把它读出来。这个例子 * 主要说明 NIO 和传统IO的不同,需要注意channel 和 buffer的使用。 * 理解 NIO 是面向缓冲的。而IO是面向流的。 * * 以下例子要理解NIO的使用 进程,1 定义1个 channel , 2,定义1个buffer * 3 向buffer写数据 (写的含义有两种,与channel有关) 4 转换为读模式 5.读取buffer数据 (读的含义与channel的方向有关) * */ public class Main { public static void main(String[] args) throws IOException { File a = new File("test.txt"); if (!a.exists()) { a.createNewFile(); } FileOutputStream out = new FileOutputStream(a); //构造输出channel,这里使用filechannel FileChannel outChannel = out.getChannel(); String testStr = "Lina , i love you"; //构造1个输出的缓存。 ByteBuffer byteBuffer1 = ByteBuffer.allocate(512); //put方法向缓存中写数据,注意是写 byteBuffer1.put(testStr.getBytes()); //下面的3行代码将向文件中写数据,filp()方法把buffer转换为读模式,然后使用channel的写方法写数据到文件。 //注意的是,outChannel 写入文件的数据是从charbuffer“读取”的, 写入或读取 是针对buffer而言,不是根据channel说的,这点需要理解 byteBuffer1.flip(); while (byteBuffer1.hasRemaining()) { outChannel.write(byteBuffer1); } outChannel.close(); out.close(); FileInputStream in = new FileInputStream(a); //构造输入channel和 buffer,跟以上对照,channel的方向是 底层的包装层决定的。 FileChannel inChannel = in.getChannel(); ByteBuffer inBuffer = ByteBuffer.allocate(512); //循环读取文件数据,写入到 buffer中,注意这里还是写入buffer while (inChannel.read(inBuffer)!=⑴) { } //转换为读模式,flip方法调用后,buffer会产生1些变化,这里暂不讨论。 inBuffer.flip(); byte[] dest = new byte[inBuffer.limit()]; //读取数据到byte数组。 inBuffer.get(dest, 0, inBuffer.limit()); inChannel.close(); in.close(); System.out.println(new String(dest)); }


Channel

官方文档定义channel指“与1个实体的连接”,这个实体可以是1个装备、文件、socket等。channel的接口定义本身简单,JDK提供了几种实现。

public interface Channel extends Closeable { public boolean isOpen(); public void close() throws IOException; }


上图展现了channel的体系,可见WritableByteChannel和ReadableByteChannel 分别扩大了channel接口,加入了读和写的功能,其中最多见的实现已分别用红色框起来,他们分别适用于不同的场合。

FileChannel 从文件中读写数据,与fileinput/outputStream对应

DatagramChannel 能通过UDP读写网络中的数据。对应DatagramSocket

SocketChannel 能通过TCP读写网络中的数据。对应IO中的socket

ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每个新进来的连接都会创建1个SocketChannel。对应IO中ServerSocket

Buffer

首先贴1张图来表示Channel和Buffer的关系,即channel是通过buffer来读写数据的。关于buffer,http://ifeve.com/buffers/ ,以上地址翻译的很好,这里摘出里面的部份内容。


基本用法

简单的例子中,已说明了channel和buffer的基本用法这里,做个简单的总结,

使用Buffer读写数据1般遵守以下4个步骤:

1.     写入数据到Buffer

2.     调用flip()方法

3.     从Buffer中读取数据

4.     调用clear()方法或compact()方法

当向buffer写入数据时,buffer会记录下写了多少数据。1旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

1旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空全部缓冲区。compact()方法只会清除已读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

Buffer的属性

buffer有3个基本的属性capacity limit position.

capacity 是指buffer的大小,在buffer建立的时候已肯定。

limit 当buffer处于写模式,指还可以写入多少数据,处于读模式,指还有多少数据可以读。

position 当buffer处于写模式,指下1个写数据的位置, 处于读模式,当前将要读取的数据的位置。每读写1个数据,position+1

也就是 limit 和position在 buffer的读/写时的含义不1样。当调用buffer的flip方法,由写模式变成读模式时,

limit(读)=position(写)

position(读) =0;

Buffer的类型

buffer有多种类型,不同的buffer提供不同的方式操作buffer中的数据。


buffer的操作

写数据

写数据到buffer有两种情况:

1.     从channel写到 buffer,如例子中channel从文件中读取数据,写到channel

2.     直接调用put方法,往里面写数据

flip()

这个操作已解释过,转换buffer为读模式

读数据

从Buffer中读取数据有两种方式:

1.     从Buffer读取数据到Channel。

2.     使用get()方法从Buffer中读取数据。

rewind()

Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,依然表示能从Buffer中读取多少个元素(byte、char等)。

clear() 和 compact()方法

1旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告知我们可以从哪里开始往Buffer里写数据。

如果Buffer中有1些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告知你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那末使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后1个未读元素正后面。limit属性仍然像clear()方法1样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------

上一篇 康托展开

下一篇 【HTML】表格标记

分享到:
------分隔线----------------------------
关闭
程序员人生