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

Channel的顶层接口:

public interface Channel extends Closeable {

  public boolean isOpen();

  public void close() throws IOException;

}

其中只包含最基本的两个方法,如下图是从《Java NIO》截取的Channel继承树。

Channel可分为可读和可写,实现了对应的可读可写的Channel接口或者抽象Channel类,就可以读写兼并。

Java 为 Channel 接口提供的最主要实现类如下:

  FileChannel:用于读取、写入、映射和操作文件的通道。

  DatagramChannel:通过 UDP 读写网络中的数据通道。

  SocketChannel:通过 TCP 读写网络中的数据。

  ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。

  以上Channel都实现或者继承了相应的Channel读写接口或者读写抽象类,所以都是可读写的。但是因为FileChannel可以根据FileInputStream或者FileOutputStream获取,所以当根据以上类获取的FileChennel进行读或者写的时候会抛出异常。

获取Channel对象:

  1. FileChannel对象的获取:

	@Test
public void test() throws IOException{
//1. 使用FileInputStream获取FileChannel
FileInputStream fis = new FileInputStream("d:\\1.txt");
FileChannel fChannel = fis.getChannel();
//2. 使用FileOutputStream获取FileChannel
FileInputStream ois = new FileInputStream("d:\\1.txt");
FileChannel fChannel1 = ois.getChannel();
//3, 使用RandomAccessFile对象获取
RandomAccessFile raf = new RandomAccessFile("d:\\1.txt", "rw");
FileChannel fChannel2 = raf.getChannel();
//4. FileChannel的open方法打开
FileChannel fChannel3 = FileChannel.open(Paths.get("d:\\1.txt"), StandardOpenOption.READ,StandardOpenOption.WRITE);
}

  

  2. 其他三个网络Channel的获取方式:

    @Test
public void test2() throws IOException{
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
ServerSocketChannel ssChannel = ServerSocketChannel.open();
DatagramChannel datagramChannel = DatagramChannel.open();
}

Channel的读写:

  1. 从Channel中读取数据到buffer

  public abstract int read(ByteBuffer dst) throws IOException;

  public abstract long read(ByteBuffer[] dsts, int offset, int length)throws IOException;

  public final long read(ByteBuffer[] dsts) throws IOException {
    return read(dsts, 0, dsts.length);
  }

  2. 将buffer中的数据写入Channel

  public abstract int write(ByteBuffer src) throws IOException;

  public abstract long write(ByteBuffer[] srcs, int offset, int length)throws IOException;

  public final long write(ByteBuffer[] srcs) throws IOException {
    return write(srcs, 0, srcs.length);
  }

  3. 如下一段文件读写的代码

public void test3() {
FileInputStream fis = null;
FileChannel inputChannel = null;
FileOutputStream fos = null;
FileChannel outputChannel = null;
try {
fis = new FileInputStream("d:\\1.txt");
inputChannel = fis.getChannel(); fos = new FileOutputStream("d:\\1.bak.txt");
outputChannel = fos.getChannel(); ByteBuffer buf = ByteBuffer.allocate(1024);
int len = -1;
while ((len = inputChannel.read(buf)) != -1) {
buf.flip();
outputChannel.write(buf);
buf.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputChannel != null) {
try {
outputChannel.close();
} catch (Exception e2) {
}
}
if (outputChannel != null) {
try {
outputChannel.close();
} catch (Exception e2) {
}
}
if (inputChannel != null) {
try {
inputChannel.close();
} catch (Exception e2) {
}
}
if (fos != null) {
try {
fos.close();
} catch (Exception e2) {
}
}
if (fis != null) {
try {
fis.close(); } catch (Exception e2) {
}
} } }

  

Channel的transferFrom和transferTo,看如下代码(为了看着简单异常直接抛出去):

public void test4() throws IOException {
FileInputStream fis = new FileInputStream("d:\\1.txt");
FileChannel inputChannel = fis.getChannel();
FileOutputStream fos = new FileOutputStream("d:\\1.bak.txt");
FileChannel outputChannel = fos.getChannel(); // 直接从通道中读,在内存中分配空间,在物理内存中直接操作
// inputChannel.transferTo(0,inputChannel.size() , outputChannel);
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
}

分散(Scatter)和聚集(Gather)

1. 分散是将一个Channel中的数据写到多个顺序的buffer中,一般是传进一个buffer数组中,Channel中的数据依次写入buffer数组中的buffer当中。

2. 聚集是将多个buffer中的数据写入同一个buffer中,一般操作是一个buffer数组。

代码如下:

@Test
public void test5() throws IOException {
FileInputStream fis = new FileInputStream("d:\\1.txt");
FileChannel inputChannel = fis.getChannel();
FileOutputStream fos = new FileOutputStream("d:\\1.bak.txt");
FileChannel outputChannel = fos.getChannel(); ByteBuffer buf1 = ByteBuffer.allocate(1024);
ByteBuffer buf2 = ByteBuffer.allocate(64);
ByteBuffer buf3 = ByteBuffer.allocate(32);
ByteBuffer[] bufs = { buf1, buf2, buf3 }; while (inputChannel.read(bufs) != -1) {
// 分散读取(Scattering Reads)
inputChannel.read(bufs);
for (ByteBuffer buf : bufs) {
buf.flip();
}
// 聚集写入(Gathering Writes)
outputChannel.write(bufs);
for (ByteBuffer buf : bufs) {
buf.clear();
}
}
}

  

Channel暂时想到这么多东西,后续有想到的再补充,开始写博客欢迎批评指正。

参看资料: 《Java NIO 中文版》

Java NIO (三) 通道(Channel)的更多相关文章

  1. Java NIO之通道Channel

    channel与流的区别: 流基于字节,且读写为单向的. 通道基于快Buffer,可以异步读写.除了FileChannel之外都是双向的. channel的主要实现: FileChannel Data ...

  2. Java NIO学习笔记---Channel

    Java NIO 的核心组成部分: 1.Channels 2.Buffers 3.Selectors 我们首先来学习Channels(java.nio.channels): 通道 1)通道基础 通道( ...

  3. NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件

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

  4. 5. 彤哥说netty系列之Java NIO核心组件之Channel

    你好,我是彤哥,本篇是netty系列的第五篇. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Java NIO的核心组件之一--Channel. 思维转变 首先, ...

  5. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  6. Java NIO之通道

    一.前言 前面学习了缓冲区的相关知识点,接下来学习通道. 二.通道 2.1 层次结构图 对于通道的类层次结构如下图所示. 其中,Channel是所有类的父类,其定义了通道的基本操作.从 Channel ...

  7. 【NIO】Java NIO之通道

    一.前言 前面学习了缓冲区的相关知识点,接下来学习通道. 二.通道 2.1 层次结构图 对于通道的类层次结构如下图所示. 其中,Channel是所有类的父类,其定义了通道的基本操作.从 Channel ...

  8. Java NIO:通道

    最近打算把Java网络编程相关的知识深入一下(IO.NIO.Socket编程.Netty) Java NIO主要需要理解缓冲区.通道.选择器三个核心概念,作为对Java I/O的补充, 以提升大批量数 ...

  9. Java NIO 之 Socket Channel

    在Java NIO中用Channel来对程序与进行I/O操作主体的连接关系进行抽象,这些IO主体包括如文件.Socket或其他设备.简而言之,指代了一种与IO操作对象间的连接关系. 按照Channel ...

  10. Java IO和Java NIO 和通道 在文件拷贝上的性能差异分析

    1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区 ...

随机推荐

  1. HBase表预分区与压缩

    1.建立HBase预分区表.sql语句如下: create 'buyer_calllogs_info_ts', 'record', {SPLITS_FILE => 'hbase_calllogs ...

  2. NYOJ 119 士兵杀敌(三) RMQ ST

    NYOJ 119 士兵杀敌(三) RMQ ST 题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=119 思路: ST在线 预处理O(nlog ...

  3. 深入解析Java垃圾回收机制

    引入垃圾回收 哪些内存需要回收? 引用计数法 可达性分析 如何回收 Marking 标记 Normal Deletion 清除 Deletion with Compacting 压缩 为什么需要分代收 ...

  4. Postgres是如何管理空值的

    创建表test,y字段插入null. test=# create table test(x bigint,y bigint,z text); CREATE TABLE test=# insert in ...

  5. Android异步消息机制

    Android中的异步消息机制分为四个部分:Message.Handler.MessageQueue和Looper. 其中,Message是线程之间传递的消息,其what.arg1.arg2字段可以携 ...

  6. js函数的作用域与this指向

    函数的作用域与this指向是js中很重要的一部分,理清这点东西需要个逻辑,看看我的逻辑怎么样... 下面是个提纲,可以直接挑你感兴趣的条目阅读. 函数的定义方式:直接定义(window下,内部定义), ...

  7. oracle用户被锁定

    sqlplus sys/password@localhost:1521/cmsx as sysdba SQL*Plus: Release 11.2.0.1.0 Production on 星期一 7月 ...

  8. caffe在windows编译project及执行mnist数据集測试

    caffe在windows上的配置和编译能够參考例如以下的博客: http://blog.csdn.net/joshua_1988/article/details/45036993 http://bl ...

  9. ORA-16032: parameter LOG_ARCHIVE_DEST_3 destination string cannot be translated问题处理过程

    1,现象是oracle启动报错例如以下: SQL> startup ORA-16032: parameter LOG_ARCHIVE_DEST_3 destination string cann ...

  10. Ansible@一个高效的配置管理工具--Ansible configure management--翻译(一)

    未经书面许可,请勿转载 ---      Ansible is the simplest way to automate apps and IT infrastructure 这是Ansible官方站 ...