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本身不能直接访问数据 ...
随机推荐
- tomcat 清理日志
clear_log.sh #!/bin/bash #clear tomcat logs #log size (1M bytes),if lt, clear LOG_FILE_SIZE=1024000 ...
- python知识点记录(一):
1.如何使print输出不换行: 在print语句末尾加上一个英文逗号. 2.安装第三方模块时,用pip和easy_install是一样的.下载一个setuptools.exe安装好就有easy_in ...
- vb6获取字符串长度
用过VB5.0或者更早版本的读者应该知道VB有一个测试字符串长度的函数: Len.但当你升级到VB6时,会发现这里的Len并没有以前那么好用了——它变成了测试字符个数而不是字符串长度.就是说,当你用以 ...
- Firebug在Firefox DevTools 中复活
英文:Firefox,编译:开源中国 链接:www.oschina.net/news/80230/firebug-lives-on-in-firefox-devtools 技术最前线转注:2016年1 ...
- Amazon Web Services
- 一个很奇怪的重复链接lib的问题
早上在调一个程序的时候感觉非常奇怪,就是数据在初始化的时候会失败,后来发现是获取一个数据的时候出错了 假设我们又一个config.lib,sql.dll和main.exe 因为数据库在打开数据库的时候 ...
- view抖动效果
1.使用属性动画 ViewPropertyAnimator.animate(webView).translationX(20).setInterpolator(new CycleInterpolato ...
- do-while语句
一.语句格式格式1:do 语句1;while (条件表达式); 格式2:do { 语句1; 语句2; -}while (条件表达式); 语句执行过程:1.执行一遍循环体.2.求出作为循环条件的 ...
- AIR call dll
commandproxy C#通讯 https://code.google.com/p/commandproxy smartrcp Java And Flex Application http://s ...
- 【原】搭建Samba的简要过程
1.安装samba yum install samba –y 2.创建用户 useradd admin #先创建系统用户 smbpasswd -a admin #第一次加入需要-a参数,把admin用 ...