Channel是一个连接到数据源的通道。程序不能直接用Channel中的数据,必须让Channel与BtyeBuffer交互数据,才能使用Buffer中的数据。

我们用FileChannel作为引子,开始逐步的了解NIO中的重要一环——Channel

FileChannel

有了前面的知识积累,我可以更快速的学习。FileChannel中常用的操作无非那么几种,打开FileChannel、用BtyeBuffer从FileChannel中读数据、用BtyeBuffer向FileChannel中写数据,下面这段代码就展示了这些

/*
* 1.Channel是需要关闭的,所以这里用TWR方式确保Channel正确关闭
* 2.鼓励大家用这种方法打开通道FileChannel.open(Path path, OpenOption... options)
*/
try (FileChannel inChannel
= FileChannel.open(Paths.get("src/a.txt"),StandardOpenOption.READ);
FileChannel outChannel
= FileChannel.open(Paths.get("src/b.txt"),StandardOpenOption.WRITE);) {
ByteBuffer buf = ByteBuffer.allocate(48);
/*
* 1.channel.write()和read()方法是需要移动position和limit指针的
* 所以需要用buffer.flip()等方法,来保证读写正确
* 2.channel.read()方法是从通道读取到缓冲区中,读取的字节数量是n (n是buffer中当前剩余的容量),
* 但是读取的数量是取决于通道的当前状态。例如:要读到文件末尾,不够buffer的容量也就是 通道剩余<=n,
* 或者说ServerSocketChannel 当前只能读取准备好的,这很可能<n,所以说加循环,
* 另外read的方法返回当前读取的数量,一个int 可以根据他来设定while
* 如果返回-1,表示到了文件末尾
*/
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
buf.flip();
/*
*注意fileChannel.write()是在while循环中调用的。
*因为无法保证write()方法一次能向FileChannel写入多少字节,
*因此需要重复调用write()方法,直到Buffer中已经没有尚未写入通道的字节。
*/
while (buf.hasRemaining()) {
outChannel.write(buf);
}
buf.clear();
bytesRead = inChannel.read(buf);
}
}

其实掌握了Buffer的知识后,学起FileChannel来挺容易的。而且再告诉你一点,就是如果只是将一个数据源通过FileChannel,转移到另一个数据源,还有一种更加简单的方法

try (FileChannel inChannel
= FileChannel.open(Paths.get("src/a.txt"),StandardOpenOption.READ);
FileChannel outChannel
= FileChannel.open(Paths.get("src/b.txt"),StandardOpenOption.WRITE);) {
//第二个参数表示,数据转移的起始位置,第三个参数表示转移的长度
//channel.size()表示通道的长度
outChannel.transferFrom(inChannel,0,inChannel.size());
//以下方式也可
inChannel.transferTo(0, inChannel.size(), outChannel);
}

这些以外,还有几个常用的方法,在这里要跟大家说一下

fileChannel.position() 返回FileChannel读写的当前位置

fileChannel.position(long newPosition) 设置FileChannel读写的当前位置

fileChannel.truncate(long size) 截取文件的前size个字节

fileChannel.force(boolean metaData) 将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。其中的boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。

下面理论上要介绍SocketChannel ServerSocketChannel等通道了,但是这些网络通道和fileChannel不太一样,因为fileChannel竟然是阻塞的(NIO,你在跟我开玩笑吧!),真的是阻塞的。而SocketChannel ServerSocketChannel等通道才是非阻塞的(fileChannel是充话费送的吧!),所以它们的真正能力要配合Selector才能显示出来,所以等到讲解Selector时,在一起讲。

那这样就结束了吗?当然不可能(这种看右边的滚动条就能发现的事实,就不要故弄玄虚了吧! 咦,我怎么在自己吐槽自己?)下面开始讲讲java7中引进的AsynchronousFileChannel,这回放心,它是异步的。

异步I/O (AIO)

其实利用java7之前的方式,也能做到,但是必须写大量的多线程代码,而且多路读取也十分麻烦。除非程序写的十分强大,否则,自己写的异步I/O的速度只能是 慢~~~~~~~~~

在java7的异步I/O中,主要有两种形式,将来式回调式。这是在java.util.concurrent中的并发工具,不会的话也没关系,在这里应该能大致的看懂。

将来式

这种方式是由主线程发起I/O操作并轮询等待结果。这里用了java.util.concurrent.Future接口,它的能力是不让当前线程阻塞。通过将I/O操作转移到另一线程上,并在完成时返回结果,来达到异步的目的。

try (AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(
Paths.get("src/a.txt"), StandardOpenOption.READ);) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
//read的第二个参数指定了channel的起始位置
Future<Integer> result = inChannel.read(buffer, 0);
//一直轮询I/O操作是否完成
while (!result.isDone()) {
// 做点别的
}
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
}

回调式

这种方式是预先制定好I/O成功或失败时的应对策略,等待I/O操作完成后就自动执行该策略。所以必须得重写两个方法completionHandler.completed()和completionHandler.failed().

try (AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(
Paths.get("src/a.txt"), StandardOpenOption.READ);) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
/*
* asynchronousFileChannel.read(ByteBuffer dst,long position,
* A attachment, CompletionHandler<Integer,? super A> handler)
* 该函数是回调式中的核心函数
* 1.首先讲最后一个参数,它的第二个泛型类型和第三个参数类型一致为A
* 该接口有两个待实现的方法,completed(...)和failed(...) 分别代指完成时和失败时如何操作
* completed(Integer result, A attachment)的第一个参数是完成了多少个字节
* failed(Throwable exc, A attachment)的第一个参数是引起失败的异常类型
* 2.A 可以理解为在CompletionHandler的实现外部,要给实现内部什么信息
* 在下面的代码中,我传的A为buffer,以便实现的内部打印buffer信息,也可以传递String类型等
* 3.前两个参数分别为与通道交互的byteBuffer和起始位置
*/
inChannel.read(buffer, 0, buffer,
new CompletionHandler<Integer, ByteBuffer>() {
public void completed(Integer result,
ByteBuffer attachment) {
System.out.println(result);
attachment.flip();
while (attachment.hasRemaining()) {
System.out.print((char) attachment.get());
}
} public void failed(Throwable exception,
ByteBuffer attachment) {
System.out.println("failed"
+ exception.getMessage());
}
}); // 做点别的
}

纵观这两种异步I/O实现方式,我自己总感觉,将来式总是询问数据是否到位,有股非阻塞I/O的感觉。网络异步I/O也是运用将来式和回调式完成的,和文件I/O基本一致,就不再磨叽。

但java7的I/O新内容绝不止这些,还有对网络多播的支持,还有通道组等等。想学完?路还有很远、很远呢。

讲的就是这么多,如有问题联系我

Java NIO教程 Channel的更多相关文章

  1. Java NIO教程 目录

    "Java NIO系列教程" 是笔者hans为NIO的初学者编写的一份入门教程,想仔细学习的同学可以按照顺序去阅读.由于我学的也不是特别的精,所以错误.疏漏在所难免,希望同学们指正 ...

  2. Java NIO 之 Channel(通道)

    历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 一 Channel ...

  3. 海纳百川而来的一篇相当全面的Java NIO教程

    目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...

  4. Java NIO 教程

    Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO. Java NIO提供了与 ...

  5. Java NIO教程 前言

    阅读本文前,建议你先了解 旧I/O NIO 是 New I/O 的缩写,要了解它真正的内涵,需要掌握的知识还是比较多的.我努力在这几篇笔记里,勾勒出整个io的面貌.为大家的深入学习铺路. I/O简史 ...

  6. Java NIO教程 MappedByteBuffer

    之前跟大家说过,要讲MappedByteBuffer,现在我来履行承诺了. 首先从大体上讲一下MappedByteBuffer究竟是什么.从继承结构上来讲,MappedByteBuffer继承自Byt ...

  7. [翻译] java NIO 教程---介绍

    原文地址:http://tutorials.jenkov.com/java-nio/index.html Java NIO(new IO)是从java1.4之后的对IO API的另一种选择,即对标准j ...

  8. [转载] Java NIO教程

    转载自并发编程网 – ifeve.com http://ifeve.com/java-nio-all/ 关于通道(Channels).缓冲区(Buffers).选择器(Selectors)的故事. 从 ...

  9. Java NIO -- 通道 Channel

    通道(Channel):由 java.nio.channels 包定义的.Channel 表示 IO 源与目标打开的连接.Channel 类似于传统的“流”.只不过 Channel本身不能直接访问数据 ...

随机推荐

  1. tomcat 清理日志

    clear_log.sh #!/bin/bash #clear tomcat logs #log size (1M bytes),if lt, clear LOG_FILE_SIZE=1024000 ...

  2. python知识点记录(一):

    1.如何使print输出不换行: 在print语句末尾加上一个英文逗号. 2.安装第三方模块时,用pip和easy_install是一样的.下载一个setuptools.exe安装好就有easy_in ...

  3. vb6获取字符串长度

    用过VB5.0或者更早版本的读者应该知道VB有一个测试字符串长度的函数: Len.但当你升级到VB6时,会发现这里的Len并没有以前那么好用了——它变成了测试字符个数而不是字符串长度.就是说,当你用以 ...

  4. Firebug在Firefox DevTools 中复活

    英文:Firefox,编译:开源中国 链接:www.oschina.net/news/80230/firebug-lives-on-in-firefox-devtools 技术最前线转注:2016年1 ...

  5. Amazon Web Services

  6. 一个很奇怪的重复链接lib的问题

    早上在调一个程序的时候感觉非常奇怪,就是数据在初始化的时候会失败,后来发现是获取一个数据的时候出错了 假设我们又一个config.lib,sql.dll和main.exe 因为数据库在打开数据库的时候 ...

  7. view抖动效果

    1.使用属性动画 ViewPropertyAnimator.animate(webView).translationX(20).setInterpolator(new CycleInterpolato ...

  8. do-while语句

    一.语句格式格式1:do  语句1;while (条件表达式); 格式2:do {  语句1;  语句2;  -}while (条件表达式); 语句执行过程:1.执行一遍循环体.2.求出作为循环条件的 ...

  9. AIR call dll

    commandproxy C#通讯 https://code.google.com/p/commandproxy smartrcp Java And Flex Application http://s ...

  10. 【原】搭建Samba的简要过程

    1.安装samba yum install samba –y 2.创建用户 useradd admin #先创建系统用户 smbpasswd -a admin #第一次加入需要-a参数,把admin用 ...