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. CF 628B New Skateboard --- 水题

    CD 628B 题目大意:给定一个数字(<=3*10^5),判断其能被4整除的连续子串有多少个 解题思路:注意一个整除4的性质: 若bc能被4整除,则a1a2a3a4...anbc也一定能被4整 ...

  2. MSP430设置串口波特率的方法

    给定一个BRCLK时钟源,波特率用来决定需要分频的因子N:               N = fBRCLK/Baudrate 分频因子N通常是非整数值,因此至少一个分频器和一个调制阶段用来尽可能的接 ...

  3. 信号处理基础概念比较----频谱vs功率谱vs能谱

    频谱: 对动态信号在频率域内进行分析,分析的结果是以频率为坐标的各种物理量的谱线和曲线,可得到各种幅值以频率为变量的频谱函数F(ω).频谱是个很不严格的东西,常常指信号的Fourier变换.频谱分析中 ...

  4. (转)分布式深度学习系统构建 简介 Distributed Deep Learning

    HOME ABOUT CONTACT SUBSCRIBE VIA RSS   DEEP LEARNING FOR ENTERPRISE Distributed Deep Learning, Part ...

  5. Junit4常用注解

    Junit4注解 JUnit4的测试类不用再继承TestCase类了.使用注解会方便很多. @Before:初始化方法@After:释放资源@Test:测试方法,在这里可以测试期望异常和超时时间@Ig ...

  6. VS2010 + Entity FrameWork 4.4 +Mvc 4.0 出现的错误

    Compiler Error Message: CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined i ...

  7. 发送短信(string转换为JSON)

    using Newtonsoft.Json;using System;using System.Collections.Generic;using System.Linq;using System.T ...

  8. 玩转单元测试之WireMock -- Web服务模拟器

    玩转单元测试之WireMock -- Web服务模拟器 WireMock 是一个灵活的库用于 Web 服务测试,和其他测试工具不同的是,WireMock 创建一个实际的 HTTP服务器来运行你的 We ...

  9. jeecg扩展封装tag的那些事

    版权声明:本文为楼主原创文章,未经楼主允许不得转载,如要转载请注明来源. 目前公司开发一直使用的是jeecg框架,简单好用,但有时候不如自己写的随心所欲.最近项目遇到一个需求, 想封装配置加解密,本来 ...

  10. LinQ To Object 基本用法

    http://www.cnblogs.com/terryzh/archive/2012/11/10/2763538.html LinQ To Object 基本用法 inq的基本语法:var resu ...