什么是通道Channel

这个说实话挺难定义的,有点抽象,不过我们可以根据它的用途来理解;

通道主要用于传输数据,从缓冲区的一侧传到另一侧的实体(如文件、套接字...),反之亦然;

通道是访问IO服务的导管,通过通道,我们可以以最小的开销来访问操作系统的I/O服务;

顺便说下,缓冲区是通道内部发送数据和接收数据的端点,如下图所示;

另外,关于通道Channel接口的定义,很简单,只有两个方法,判断通道是否打开和关闭通道;

public interface Channel extends Closeable {

    public boolean isOpen();

    public void close() throws IOException;

}

创建通道

通道主要分为两大类,文件(File)通道和套接字(socket)通道;

涉及的类有FileChannel类和三个socket通道类:SocketChannel、ServerSocketChannel和DatagramChannel;

下面分别看下这几个通道是如何创建的:

创建FileChannel通道

FileChannel通道只能通过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream对象上调用getChannel( )方法来获取,如下所示:

        RandomAccessFile raf = new RandomAccessFile ("somefile", "r");
FileChannel fc = raf.getChannel( );

创建SocketChannel通道

        SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("somehost", someport));

创建ServerSocketChannel通道

        ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(somelocalport));

创建DatagramChannel通道

        DatagramChannel dc = DatagramChannel.open( );

使用通道

在使用通道的时候,我们通常都将通道的数据取出存入ByteBuffer对象或者从ByteBuffer对象中获取数据放入通道进行传输;

在使用通道的过程中,我们要注意通道是单向通道还是双向通道,单向通道只能读或写,而双向通道是可读可写的;

如果一个Channel类实现了ReadableByteChannel接口,则表示其是可读的,可以调用read()方法读取;

如果一个Channel类实现了WritableByteChannel接口,则表示其是可写的,可以调用write()方法写入;

如果一个Channel类同时实现了ReadableByteChannel接口和WritableByteChannel接口则为双向通道,如果只实现其中一个,则为单向通道;

如ByteChannel就是一个双向通道,实际上ByteChannel接口本身并不定义新的API方法,它是一个聚集了所继承的多个接口,并重新命名的便捷接口;

如下是一个使用通道的例子,展示了两个通道之间拷贝数据的过程,已添加了完整的注释:

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel; public class Main
{ public static void main(String[] args) throws IOException
{
ReadableByteChannel source = Channels.newChannel(System.in);
WritableByteChannel dest = Channels.newChannel(System.out);
channelCopy1(source, dest);
// channelCopy2 (source, dest);
source.close();
dest.close(); } private static void channelCopy1(ReadableByteChannel src, WritableByteChannel dest)
throws IOException
{
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1)
{
// 切换为读状态
buffer.flip();
// 不能保证全部写入
dest.write(buffer);
// 释放已读数据的空间,等待数据写入
buffer.compact();
}
// 退出循环的时候,由于调用的是compact方法,缓冲区中可能还有数据
// 需要进一步读取
buffer.flip();
while (buffer.hasRemaining())
{
dest.write(buffer);
}
} private static void channelCopy2(ReadableByteChannel src, WritableByteChannel dest)
throws IOException
{
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1)
{
// 切换为读状态
buffer.flip();
// 保证缓冲区的数据全部写入
while (buffer.hasRemaining())
{
dest.write(buffer);
}
// 清除缓冲区
buffer.clear();
}
// 退出循环的时候,由于调用的是clear方法,缓冲区中已经没有数据,不需要进一步处理
} }

关闭通道

我们可以通过调用close()方法来关闭通道;

一个打开的通道代表与一个特定I/O服务的特定连接,并封装该连接的状态。当通道关闭时,这个连接会丢失,然后通道将不再连接任何东西。

可以通过isOpen()方法来判断通道是否打开,如果对关闭的通道进行读写等操作,会导致ClosedChannelException异常;

另外,如果一个通道实现了InterruptibleChannel接口,那么,当该通道上的线程被中断时,通道会被关闭,且该线程会抛出ClosedByInterruptException异常;

参考资料

《Java NIO》

Java NIO中的通道Channel(一)通道基础的更多相关文章

  1. Java NIO系列教程(五) 通道之间的数据传输

    在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel. transferFro ...

  2. java NIO中的buffer和channel

    缓冲区(Buffer):一,在 Java NIO 中负责数据的存取.缓冲区就是数组.用于存储不同数据类型的数据 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区:ByteBufferC ...

  3. Java NIO学习笔记五 FileChannel(文件通道)

    Java NIO FileChannel Java NIO FileChannel是连接文件的通道.使用FileChannel,您可以从文件中读取数据和将数据写入文件.Java NIO FileCha ...

  4. 转:Java NIO系列教程(二) Channel

    Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...

  5. Java NIO中核心组成和IO区别

    1.Java NIO核心组件 Java NIO中有很多类和组件,包括Channel,Buffer 和 Selector 构成了核心的API.其它组件如Pipe和FileLock是与三个核心组件共同使用 ...

  6. Java NIO中的Buffer 详解

    Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的.缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...

  7. Java NIO中的缓冲区Buffer(一)缓冲区基础

    什么是缓冲区(Buffer) 定义 简单地说就是一块存储区域,哈哈哈,可能太简单了,或者可以换种说法,从代码的角度来讲(可以查看JDK中Buffer.ByteBuffer.DoubleBuffer等的 ...

  8. Java NIO(二) Channel

    Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...

  9. Java NIO 三大组件之 Channel

    Java NIO 之 Channel 一.什么是Channel Channel用于源节点(例如磁盘)与目的节点的连接,它可以进行读取,写入,映射和读/写文件等操作. 在Java NIO中负责缓冲区中数 ...

  10. 转载Java NIO中的Files类的使用

    Java NIO中的Files类(java.nio.file.Files)提供了多种操作文件系统中文件的方法. Files.exists() Files.exits()方法用来检查给定的Path在文件 ...

随机推荐

  1. java编译时出现——注:使用了未经检查或不安全的操作。注:有关详细信息,请使用 -Xlint:unchecked 重新编译

    网上说是泛型问题 private List<Product> products = new ArrayList<Product>(); 这种用法绝对没错!(因为是照着书写的)在 ...

  2. Xadmin显示视图

    .display显示要设置的字段 1. 自定义样式类,显示出要显示的字段,在这个类中,也可以设置对应函数. list_display=[check,"title",delete]2 ...

  3. java【基础】日期操作

    主要是date类,SimpleDateFormat类以及Calendar类的使用. date表示日期,simpleDateFormat 表示日期格式化,Calendar一般用来做时间的操作,比如加减天 ...

  4. linux就该这么学,第十天了

    今天老师主要让要考试的提前预习课程了,提前预习, 今天讲了,防火墙,iptable.firewall-config,firewall-cmd   防火墙和网卡的配置方法,四种,1配置文件方法,主要开启 ...

  5. python3 第二十四章 - 函数式编程之Anonymous function(匿名函数)

    匿名函数指一类无须定义标识符的函数或子程序.Python用lambda语法定义匿名函数,只需用表达式而无需申明.lambda语法的定义如下: lambda [arg1 [,arg2, ... argN ...

  6. .NET Core 中使用GB2312编码报错的问题

    错误描述 环境 dotnet 2.1.4 现象 当代码中使用 System.Text.Encoding.GetEncoding("GB2312") //或者 System.Text ...

  7. boost--日期处理

    1.timer 不同于系统函数的timer()一般生成一个定时器,boost中的timer是一个计时器,以秒为单位,最小精度为毫秒,使用需要包含头文件"boost\timer.hpp&quo ...

  8. std::string的拷贝赋值研究

    说明:以下涉及的std::string的源代码摘自4.8.2版本.结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址. // std::string类定义type ...

  9. 【repost】H5的新特性及部分API详解

    h5新特性总览 移除的元素 纯表现的元素: basefont.big.center.font等 对可用性产生负面影响的元素: frame.frameset.noframes 新增的API 语义: 能够 ...

  10. Crontab定时执行Oracle存储过程

    Crontab定时执行Oracle存储过程 需求描述 我们有一个Oracle的存储过程,里面是每个月需要执行一下,生成报表,然后发送给业务部门,这一个功能我们有实现在系统的前台界面(如图1-1),但是 ...