通道(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. Activity讲解

    Activity Activity 是 Android 应用的重要组成单元之一(另外三个是 Service.BroadcastReceiver 和 ContentProvider),而 Activit ...

  2. Unity20172.0 Android平台打包

    Android SDK及Jdk百度网盘下载链接:https://pan.baidu.com/s/1dFbEmdz 密码:pt7b Unity20172.0 Android平台打包 简介说明: 第一步: ...

  3. C#.Net与MATLAB集成

    在数学分析工具方面,MATLAB无疑是佼佼者,除了作为软件工具外,MATLAB的自定义编程语言以及混合编程的支持,使其可以与Python.R之类数学分析语言媲美.尤其是在一些传统领域的研究,由于其研究 ...

  4. codeforces 893C Rumor 前向星+dfs

    893C Rumor 思路: 前向星+DFS 代码: #include <bits/stdc++.h> using namespace std; #define _for(i,a,b) f ...

  5. 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线

    题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...

  6. CCF-201412-2-Z字形扫描

    问题描述 试题编号: 201412-2 试题名称: Z字形扫描 时间限制: 2.0s 内存限制: 256.0MB 问题描述: 问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zi ...

  7. Springboot读取配置文件及自定义配置文件

    1.创建maven工程,在pom文件中添加依赖 <parent> <groupId>org.springframework.boot</groupId> <a ...

  8. .NET版支付宝商户会员卡接入

    最近公司计划对接支付宝会员卡功能,而任务恰巧由领导安排给我这边,小弟之前也未做过支付宝接口,研究了三天,终于将支付宝会员卡API接口大体上调通了,现将其整理下,以供参考. 蚂蚁金服开发平台-商户会员卡 ...

  9. JavaWeb学习总结(二)——Tomcat服务器学习和使用(一)(转)

    转载自 http://www.cnblogs.com/xdp-gacl/p/3734395.html 一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的serve ...

  10. 剑指Offer_6_从尾到头打印链表

    题目描述        输入应该链表的头节点 , 从尾到头反过来打印出每个节点的值.链表定义如下 : typedef struct ListNode { int m_nKey ; ListNode * ...