详解 通道 (Channel 接口)
在本篇博文中,本人主要讲解NIO 的两个核心点 —— 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer),
有关NIO流的其他知识点请观看本人博文《详解 NIO流》
@
通道 (Channel)
概述:
由 java.nio.channels 包定义的。
Channel 表示 IO 源与目标打开的连接。
Channel 类似于传统的“流”。
只不过 Channel本身不能直接访问数据, Channel 只能与Buffer 进行交互!
下面,本人来通过一张图展示下我们用NIO流进行数据读写的底层实现步骤:

现在,本人来展示下 Channel 接口的实现类的对象的获取手段:
手段1: 获取通道的一种方式是对支持通道的对象调用getChannel() 方法:
- public FileChannel getChannel()
支持通道的类如下:
本地I/O:
FileInputStream
FileOutputStream
RandomAccessFile
网络 I/O:
DatagramSocket
Socket
ServerSocket
手段2:
使用 Files 类的静态方法 newByteChannel()方法 获取字节通道。
- static SeekableByteChannel newByteChannel(Path path, OpenOption... options)
打开或创建一个文件,返回一个可寻址的字节通道存取文件。- static SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs)
打开或创建一个文件,返回一个可寻址的字节通道存取文件
手段3:
通过 Channel 接口 的静态方法 open()方法 打开并返回指定通道。
- static FileChannel open(Path path, OpenOption... options)
在我们获得了 Channel 接口 的实现类的对象之后,
进行信息的传输:
- public void write(ByteBuffer dst):
将 Buffer 中数据写入 Channel- public void read(ByteBuffer dst):
从 Channel 读取数据到 Buffer
判断可用性:
- void close()
关闭此通道- boolean isOpen()
告诉是否这个通道是打开的
那么,在本篇博文中,本人主要讲解下 Channel 接口实现类中的 FileChannel类:
FileChannel 类:
获得对象的手段在上文中已经讲解过了,本人就不讲解这个类的构造方法了
(一般不会有要求通过构造方法来获取Channel的对象)
那么,本人来展示下这个类的常用API:
- int read(ByteBufferdst):
从Channel中读取数据到ByteBuffer- long read(ByteBuffer[] dsts):
将Channel中的数据“分散”到ByteBuffer[]- int write(ByteBuffer src):
将ByteBuffer中的数据写入到Channel- long write(ByteBuffer[] srcs):
将ByteBuffer[]中的数据“聚集”到Channel- long position():
返回此通道的文件位置- FileChannel position(long p):
设置此通道的文件位置- long size():
返回此通道的文件的当前大小- FileChannel truncate(long s):
将此通道的文件截取为给定大小- void force(boolean metaData):
强制将所有对此通道的文件更新写入到存储设备中
那么,现在,本人来分别展示下使用 FileChannel 类 和 非直接缓冲区/直接缓冲区 来进行文件的复制操作:
首先是 Channel 接口 和 非直接缓冲区 版本:
package edu.youzg.about_nio.core;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileCopy {
    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("plantsVSzombies.mp4");
        FileOutputStream out = new FileOutputStream("copyViewFile.mp4");
        //获取通道
        FileChannel inChannel = in.getChannel();
        FileChannel outChannel = out.getChannel();
        //面向通道,和缓冲区来复制文件
        //分配一个非直接缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //读写文件
        while (inChannel.read(byteBuffer) != -1){
            //切换读取模式
            byteBuffer.flip();
            //写数据
            outChannel.write(byteBuffer);
            //清空缓冲区
            byteBuffer.clear();
        }
        //释放资源
        in.close();
        out.close();
        inChannel.close();
        outChannel.close();
    }
}
首先,本人展示下源文件的信息:

现在,本人来展示下生成文件的信息:

那么,本人再来展示下使用 FileChannel 类 和 直接缓冲区 进行文件复制:
package edu.youzg.about_nio.core;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileCopy {
    public static void main(String[] args) throws IOException {
        //通过文件通道的静态方法,打开读写通道
        //参1:通过Paths获取源文件的路径
        //参2:操作模式 StandardOpenOption.READ 读取模式
        //打开读取文件的通道
        FileChannel in = FileChannel.open(Paths.get("copyViewFile.mp4"), StandardOpenOption.READ);
        //打开写入的通道 模式要读还要写  StandardOpenOption.CREATE 意思是文件不存在就创建,如果存在就覆盖
        //StandardOpenOption.CREATE_NEW 意思是文件不存在就创建,如果存在就报错
        FileChannel out = FileChannel.open(Paths.get("copyViewFile2.mp4"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //操作内存映射文件(也就是这个缓冲区在物理内存中)
        MappedByteBuffer inByteBuffer = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());
        MappedByteBuffer outByteBuffer = out.map(FileChannel.MapMode.READ_WRITE, 0, in.size());
        //直接对缓冲区进行读写操作
        byte[] bytes = new byte[inByteBuffer.limit()];
        inByteBuffer.get(bytes);
        outByteBuffer.put(bytes);
        //释放资源
        in.close();
        out.close();
    }
}
现在,本人来展示下生成文件的信息:

现在,本人来介绍一下通道的转换性质:
通道的转换性质 主要依靠如下两个方法实现:
- public abstract long transferFrom(ReadableByteChannel src, long position, long count):
将字节从给定的可读字节通道(即:输入通道)传输到这个通道的文件中- public abstract long transferTo(long position, long count, WritableByteChannel target):
将字节从这通道的文件给出到可写字节通道(即:输出通道)
那么,现在,本人来通过这两个方法,实现下文件的复制操作:
package edu.youzg.about_nio.core;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileCopy {
    public static void main(String[] args) throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("copyViewFile2.mp4"), StandardOpenOption.READ);
        FileChannel outChannel1 = FileChannel.open(Paths.get("copyViewFile3.mp4"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        FileChannel outChannel2 = FileChannel.open(Paths.get("copyViewFile4.mp4"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //站在输入通道的角度
        inChannel.transferTo(0,inChannel.size(),outChannel1);
        //站在输出通道的角度
        outChannel2.transferFrom(inChannel,0,inChannel.size());
    }
}
那么,现在,本人来展示下生成的文件的信息:

 那么,可以看到,文件的复制成功了!
那么,可以看到,文件的复制成功了!
在本篇博文的最后,本人讲解下一个很重要的思想 —— 分散 (Scatter) 和 聚集 (Gather):
分散 (Scatter) 和 聚集 (Gather):
简介:
所谓的分散和聚集,
就是 分散读取、聚集写入
那么,本人现在来解释下这两个名词:
分散读取( Scattering Reads ):从 Channel 中读取的数据“分散”到多个Buffer缓冲区中
聚集写入( Gathering Writes ):将多个 Buffer缓冲区 中的数据“聚集”到 Channel
本人现在通过两张图来展示下这两个知识点:
- 分散读取( Scattering Reads ): 
  (注意:按照缓冲区的顺序,从Channel中读取的数据依次将Buffer填满) (注意:按照缓冲区的顺序,从Channel中读取的数据依次将Buffer填满)
- 聚集写入( Gathering Writes ): 
  
 (注意:按照缓冲区的顺序,写入position和limit之间的数据到Channel)
那么,现在,本人来利用这两个知识点,来实现下文件的复制操作:
package edu.youzg.about_nio.core;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileCopy {
    public static void main(String[] args) throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("copyViewFile4.mp4"), StandardOpenOption.READ);
        FileChannel outChanle = FileChannel.open(Paths.get("copyViewFile5.mp4"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //分配多个缓冲区(缓冲区要分配得足够)
        ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024*2);
        ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024*1024*20);
        //定义一个数组
        ByteBuffer[] byteBuffers={byteBuffer1,byteBuffer2};
        //分散
        inChannel.read(byteBuffers);
        //聚集
        for (ByteBuffer byteBuffer : byteBuffers) {
            byteBuffer.flip();//转换成读取模式
        }
        //写出数据
        outChanle.write(byteBuffers);
        //释放资源
        outChanle.close();
        inChannel.close();
    }
}
现在,本人来展示下生成的文件:

那么,可以看到,文件复制成功了!
(本人 NIO流 博文链接:https:////www.cnblogs.com/codderYouzg/p/12418765.html)
详解 通道 (Channel 接口)的更多相关文章
- pika详解(四) channel 通道
		pika详解(四) channel 通道 本文链接:https://blog.csdn.net/comprel/article/details/94662394 版权  channel通道 通道 ... 
- 详解 迭代器 —— Iterator接口、 ListIterator接口 与 并发修改异常
		(请关注 本人"Collection集合"博文--<详解 Collection集合>) Iterator接口(迭代器): 概述: 对 collection 进行迭代的迭 ... 
- cgkib动态代理详解-不依赖接口,速度快
		1. cglib原理-不依赖接口,速度快 使用ASM字节框架动态生成要代理类的子类,子类重写final以外的方法,织入横切逻辑 2. 示例-实现MethodInterceptor Test.java ... 
- java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口
		函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ... 
- 详解JAVA8函数式接口{全}
		1: 函数式接口 1.1 概念 1.2 格式 1.3@FunctionalInterface注解 1.4 调用自定义函数接口 2:函数式编程 2.1:lambda的延迟执行 2.2 使用Lambda作 ... 
- 详解 NIO流
		在观看本篇博文前,建议先观看本人博文 -- <详解 IO流> NIO流: 首先,本人来介绍下什么是NIO流: 概述: Java NIO ( New IO )是从 Java 1.4 版本开始 ... 
- 详解 缓冲区(Buffer 抽象类)
		在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ... 
- c#接口使用详解
		c#接口使用详解 c#中接口隐式与显示实现 c#中接口可以隐式实现.显示实现,隐式实现更常使用.显示实现较少使用 其区别在于 显示实现避免接口函数签名冲突 显示实现只可以以接口形式调用 显示实现其子类 ... 
- 详解 List接口
		本篇博文所讲解的这两个类,都是泛型类(关于泛型,本人在之前的博文中提到过),我们在学习C语言时,对于数据的存储,用的差不多都是数组和链表. 但是,在Java中,链表就相对地失去了它的存在价值,因为Ja ... 
随机推荐
- javaAPI操作ES分组聚合
			连接es的客户端使用的 TransportClient SearchRequestBuilder requestBuilder = transportClient.prepareSearch(indi ... 
- 微信公众平台 分享 关注 js功能代码
			转上一篇文章 微信很火,微信推出的公众平台也吸引了一部分市场宣传推广团队,像冷笑话大全这种微博养粉大户在微信的公众平台也是异常火爆. 因工作需求,最近为我们的市场部做了几个微信公共平台下的页面,其中涉 ... 
- msys2 mingw64安装
			(1)安装msys2 (2)更新\etc\pacman.d\下的源文件 mirrorlist.msys Server = http://repo.msys2.org/msys/$arch/ Serve ... 
- HDU - 1962 二分图最大匹配模板(扑克牌得分最大)
			题意: 直接说数据,第一行给定几组数据,每一组数据的第一行是两个人扑克牌分别的数量,第一行是亚当的扑克牌,第二行是夏娃的扑克牌,每一个扑克牌的大小用两个字符来表示,第一个表示是几号扑克牌,第二个表示扑 ... 
- Fast Enumeration
			在 Objective-C 2.0 中提供了快速枚举的语法,它是我们遍历集合元素的首选方法.它具有以下优点: 比直接使用 NSEnumerator 更高效: 语法非常简洁: 如果集合在遍历的过程中被修 ... 
- MySQL:锁机制和隔离事务级别
			在mysql中的锁看起来是很复杂的,因为有一大堆的东西和名词:排它锁,共享锁,表锁,页锁,间隙锁,意向排它锁,意向共享锁,行锁,读锁,写锁,乐观锁,悲观锁,死锁.这些名词有的博客又直接写锁的英文的简写 ... 
- layuiadmin使用Ueditor 获取不了数据的解决方法
			表单根元素请使用form元素,layuiadmin 默认使用div作为表单根元素. <form class="layui-form"> <textarea nam ... 
- 论redis的内存占用
			目前大部分成程序员都将一些数据放入到了缓存(redis)中,但是你是否对这个redis内存占用了解呢?下面我们就来说一下redis的内存最优使用: 1.我们首先来介绍一下我们在存入大量数据到redis ... 
- B [JLOI2012]树
			时间限制 : - MS 空间限制 : - KB 评测说明 : 1s,128m 问题描述 在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点 ... 
- 201771010108-韩腊梅 实验一 软件工程准备—<对软件工程的初步了解>
			项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/nwnu2020SE 这个作业要求链接 https://www.cnblogs.com/nwnu- ... 
