Java NIO教程 Channel
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的更多相关文章
- Java NIO教程 目录
"Java NIO系列教程" 是笔者hans为NIO的初学者编写的一份入门教程,想仔细学习的同学可以按照顺序去阅读.由于我学的也不是特别的精,所以错误.疏漏在所难免,希望同学们指正 ...
- Java NIO 之 Channel(通道)
历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 一 Channel ...
- 海纳百川而来的一篇相当全面的Java NIO教程
目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...
- Java NIO 教程
Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO. Java NIO提供了与 ...
- Java NIO教程 前言
阅读本文前,建议你先了解 旧I/O NIO 是 New I/O 的缩写,要了解它真正的内涵,需要掌握的知识还是比较多的.我努力在这几篇笔记里,勾勒出整个io的面貌.为大家的深入学习铺路. I/O简史 ...
- Java NIO教程 MappedByteBuffer
之前跟大家说过,要讲MappedByteBuffer,现在我来履行承诺了. 首先从大体上讲一下MappedByteBuffer究竟是什么.从继承结构上来讲,MappedByteBuffer继承自Byt ...
- [翻译] java NIO 教程---介绍
原文地址:http://tutorials.jenkov.com/java-nio/index.html Java NIO(new IO)是从java1.4之后的对IO API的另一种选择,即对标准j ...
- [转载] Java NIO教程
转载自并发编程网 – ifeve.com http://ifeve.com/java-nio-all/ 关于通道(Channels).缓冲区(Buffers).选择器(Selectors)的故事. 从 ...
- Java NIO -- 通道 Channel
通道(Channel):由 java.nio.channels 包定义的.Channel 表示 IO 源与目标打开的连接.Channel 类似于传统的“流”.只不过 Channel本身不能直接访问数据 ...
随机推荐
- CF 628B New Skateboard --- 水题
CD 628B 题目大意:给定一个数字(<=3*10^5),判断其能被4整除的连续子串有多少个 解题思路:注意一个整除4的性质: 若bc能被4整除,则a1a2a3a4...anbc也一定能被4整 ...
- MSP430设置串口波特率的方法
给定一个BRCLK时钟源,波特率用来决定需要分频的因子N: N = fBRCLK/Baudrate 分频因子N通常是非整数值,因此至少一个分频器和一个调制阶段用来尽可能的接 ...
- 信号处理基础概念比较----频谱vs功率谱vs能谱
频谱: 对动态信号在频率域内进行分析,分析的结果是以频率为坐标的各种物理量的谱线和曲线,可得到各种幅值以频率为变量的频谱函数F(ω).频谱是个很不严格的东西,常常指信号的Fourier变换.频谱分析中 ...
- (转)分布式深度学习系统构建 简介 Distributed Deep Learning
HOME ABOUT CONTACT SUBSCRIBE VIA RSS DEEP LEARNING FOR ENTERPRISE Distributed Deep Learning, Part ...
- Junit4常用注解
Junit4注解 JUnit4的测试类不用再继承TestCase类了.使用注解会方便很多. @Before:初始化方法@After:释放资源@Test:测试方法,在这里可以测试期望异常和超时时间@Ig ...
- VS2010 + Entity FrameWork 4.4 +Mvc 4.0 出现的错误
Compiler Error Message: CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined i ...
- 发送短信(string转换为JSON)
using Newtonsoft.Json;using System;using System.Collections.Generic;using System.Linq;using System.T ...
- 玩转单元测试之WireMock -- Web服务模拟器
玩转单元测试之WireMock -- Web服务模拟器 WireMock 是一个灵活的库用于 Web 服务测试,和其他测试工具不同的是,WireMock 创建一个实际的 HTTP服务器来运行你的 We ...
- jeecg扩展封装tag的那些事
版权声明:本文为楼主原创文章,未经楼主允许不得转载,如要转载请注明来源. 目前公司开发一直使用的是jeecg框架,简单好用,但有时候不如自己写的随心所欲.最近项目遇到一个需求, 想封装配置加解密,本来 ...
- LinQ To Object 基本用法
http://www.cnblogs.com/terryzh/archive/2012/11/10/2763538.html LinQ To Object 基本用法 inq的基本语法:var resu ...