Java之NIO(一)Channel和Buffer

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,本品文章着重介绍前两种。

一个简单例子

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

http://ifeve.com/channels/

/**
 * NIO 简单测试例子,向一个文件中写入数据,然后把它读出来。这个例子
 * 主要说明 NIO 和传统IO的不同,需要注意channel 和 buffer的使用。
 * 理解 NIO 是面向缓冲的。而IO是面向流的。
 *
 * 以下例子要理解NIO的使用 过程,1 定义一个 channel , 2,定义一个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";
		//构造一个输出的缓存。
		ByteBuffer byteBuffer1 = ByteBuffer.allocate(512);

		//put方法向缓存中写数据,注意是写
	     byteBuffer1.put(testStr.getBytes());
		//下面的三行代码将向文件中写数据,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)!=-1) {
		}
		//转换为读模式,flip方法调用后,buffer会发生一些变化,这里暂不讨论。
		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指“与一个实体的连接”,这个实体可以是一个设备、文件、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服务器那样。对每一个新进来的连接都会创建一个SocketChannel。对应IO中ServerSocket

Buffer

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

基本用法

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

使用Buffer读写数据一般遵循以下四个步骤:

1.     写入数据到Buffer

2.     调用flip()方法

3.     从Buffer中读取数据

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

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

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

Buffer的属性

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

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

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

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

也就是 limit 和position在 buffer的读/写时的含义不一样。当调用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()方法

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

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

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

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

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

时间: 2024-08-29 04:54:02

Java之NIO(一)Channel和Buffer的相关文章

Java NIO(1)----Channel 和 Buffer

Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的API.其它组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类.因此,在概述中我将集中在这三个组件上.其它组件会在单独的章节中讲到. Channel 和 Buffer 基本上,所有的 IO 在NIO 中都从一个Channel 开始.Channel 有点

NIO之Channel、Buffer

前言 Java NIO 由以下几个核心部分组成: 1 .Buffer 2.Channel 3.Selector 传统的IO操作面向数据流,意味着每次从流中读一个或多个字节,直至完成,数据没有被缓存在任何地方. NIO操作面向缓冲区,数据从Channel读取到Buffer缓冲区,随后在Buffer中处理数据. 本文着重介绍Channel和Buffer的概念以及在文件读写方面的应用和内部实现原理. Buffer A buffer is a linear, finite sequence of ele

java的nio之:java的nio系列教程之channel的概念

一:java的nio的channel Java NIO的通道类似流,但又有些不同: ==>既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. ==>通道可以异步地读写. ==>通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入. 正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道.如下图所示: 二:java的nio的channel的实现 这些是Java NIO中最重要的通道的实现: ==>FileChannel  : ==>

java的nio之:java的nio系列教程之概述

一:java的nio的核心组件?Java NIO 由以下几个核心部分组成: ==>Channels ==>Buffers ==>Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的API.其它组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类.因此,在概述中我将集中在这三个组件上.其它组 件会在单独的章节中讲到. Channel 和 Buffer 基本上,所有的 IO 在

Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO https://blog.csdn.net/column/details/21963.html 部分代码会放在我的的Github:https://github.com/h2pl/ J

java NIO-Channel

基本简介 Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中. Java NIO: Non-blocking IO(非阻塞IO) Java

java nio之 channel通道(二)

java nio 通道上一篇文章里就讲述过,channel总是写数据的时候,要先把数据写入到bytebuffer,读数据的时候总是要先从channel中读入到bytebuffer.如下图,这个图是好多知名博客常用的图,很好理解这个channel. channel分为一下几种: FileChannel SocketChannel ServerSocketChannel DatagramChannel FileChannel: 经常说的FileChannel都是拿下面的例子说事 代码如下: pack

JAVA NIO 之Channel

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.Channel 通道就是将数据传输给 ByteBuffer 对象或者从 ByteBuffer 对象获取数据进行传输. Channel 用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据.常用Channel有FileChannel.SocketChannel.DatagramChannel.ServerSocketChannelSocket 可以通过socket 通道的工厂方法直接创建.但是FileChan

NIO学习:使用Channel、Buffer写入文件

NIO的效率要高于标准IO,因为NIO将最耗时的IO操作(填充和提取缓冲区)转移会操作系统.NIO以块为单位传输数据,相比标准IO的以字节为单位效率要高很多. 通道和缓冲时NIO的核心对象,每个NIO操作都要使用到它们. 通道是对流的模拟,但与流不同,通道的传输是双向的,一个通道可以同时用于读和写. 缓冲区是一个容器,它包含将要写入或者刚读出的数据.使用通道进行读写时都要经过缓冲区. 使用NIO写入文件,可以通过文件流获取通道 FileOutputStream outputStream=new