在本篇博文中,本人主要讲解NIO 的两个核心点 —— 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer),

有关NIO流的其他知识点请观看本人博文《详解 NIO流》


@


通道 (Channel)

概述:

由 java.nio.channels 包定义的。

Channel 表示 IO 源与目标打开的连接

Channel 类似于传统的“流”

只不过 Channel本身不能直接访问数据Channel 只能与Buffer 进行交互!

下面,本人来通过一张图展示下我们用NIO流进行数据读写的底层实现步骤:


现在,本人来展示下 Channel 接口的实现类的对象的获取手段:

手段1: 获取通道的一种方式是对支持通道的对象调用getChannel() 方法:

  • public FileChannel getChannel()

    支持通道的类如下
  1. 本地I/O

    FileInputStream

    FileOutputStream

    RandomAccessFile

  2. 网络 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

本人现在通过两张图来展示下这两个知识点:

  1. 分散读取( Scattering Reads ):

    (注意:按照缓冲区的顺序,从Channel中读取的数据依次将Buffer填满

  2. 聚集写入( 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 接口)的更多相关文章

  1. pika详解(四) channel 通道

    pika详解(四) channel 通道   本文链接:https://blog.csdn.net/comprel/article/details/94662394 版权 ​ channel通道 通道 ...

  2. 详解 迭代器 —— Iterator接口、 ListIterator接口 与 并发修改异常

    (请关注 本人"Collection集合"博文--<详解 Collection集合>) Iterator接口(迭代器): 概述: 对 collection 进行迭代的迭 ...

  3. cgkib动态代理详解-不依赖接口,速度快

    1. cglib原理-不依赖接口,速度快 使用ASM字节框架动态生成要代理类的子类,子类重写final以外的方法,织入横切逻辑 2. 示例-实现MethodInterceptor Test.java ...

  4. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  5. 详解JAVA8函数式接口{全}

    1: 函数式接口 1.1 概念 1.2 格式 1.3@FunctionalInterface注解 1.4 调用自定义函数接口 2:函数式编程 2.1:lambda的延迟执行 2.2 使用Lambda作 ...

  6. 详解 NIO流

    在观看本篇博文前,建议先观看本人博文 -- <详解 IO流> NIO流: 首先,本人来介绍下什么是NIO流: 概述: Java NIO ( New IO )是从 Java 1.4 版本开始 ...

  7. 详解 缓冲区(Buffer 抽象类)

    在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ...

  8. c#接口使用详解

    c#接口使用详解 c#中接口隐式与显示实现 c#中接口可以隐式实现.显示实现,隐式实现更常使用.显示实现较少使用 其区别在于 显示实现避免接口函数签名冲突 显示实现只可以以接口形式调用 显示实现其子类 ...

  9. 详解 List接口

    本篇博文所讲解的这两个类,都是泛型类(关于泛型,本人在之前的博文中提到过),我们在学习C语言时,对于数据的存储,用的差不多都是数组和链表. 但是,在Java中,链表就相对地失去了它的存在价值,因为Ja ...

随机推荐

  1. 从阿里、腾讯的面试真题中总结了这11个Redis高频面试题

    前言 现在大家的工作生活基本已经是回归正轨了,最近也是迎来了跳槽面试季,有些人已经拿到了一两个offer了. 这段时间收集了阿里.腾讯.百度.京东.美团.字节跳动等公司的Java面试题,总结了Redi ...

  2. WePY框架 input,checkbox-group,radio-group等change 一般处理方法

    布局搞定了,接下来就是数据处理方面了 form表单中常用标签,绑定change方法: 方法的具体实现 根据打印出来e的结果可以看到,e指代当前标签对象,包含属性方法等 从detail中可以获取多选框选 ...

  3. 【LeetCode】15.三数之和

    题目描述 1. 三数之和 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组. 注意: ...

  4. 将Python执行代码打包成exe可执行文件

    安装pyinstaller pip3 install pyinstaller 进入py文件目录,执行以下指令 pyinstaller -F -w <文件名.py>,-F代表生成可执行文件, ...

  5. [tyvj2032]升降梯上<dp&spfa>

    题目背景 开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道.一辆停在轨道底部的电梯.和电梯内一杆控制电梯升降的巨大手柄. 题目描述 Nescafe 之 ...

  6. 广告行业中那些趣事系列8:详解BERT中分类器源码

    最新最全的文章请关注我的微信公众号:数据拾光者. 摘要:BERT是近几年NLP领域中具有里程碑意义的存在.因为效果好和应用范围广所以被广泛应用于科学研究和工程项目中.广告系列中前几篇文章有从理论的方面 ...

  7. 实验十--- MySQL过程式数据库对象

    实验十 MySQL过程式数据库对象 一.  实验内容: 1. 存储过程的创建和调用 2. 存储函数的创建和调用 3. 触发器的创建和触发 4. 事件的创建和修改 一.  实验项目:员工管理数据库 用于 ...

  8. 汇编学习二-VB(常见函数分析)

    VB代码如下所示 push ebp 00401FF1 . 8BEC mov ebp,esp 00401FF3 . 83EC 0C sub esp,0xC push <jmp.&MSVBV ...

  9. 我是如何从通信转到Java软件开发工程师的?

    我的读者里面有绝大部分都是在校学生,有本科的,也有专科的,我在微信里收到很多读者的提问,大部分问题都跟如何学习编程有关,有换专业自学的.有迷茫不知道如何学习的.有报培训班没啥效果的等等,我能感受到他们 ...

  10. Docker的MySQL镜像, 实行数据,配置信息,日志持久化

    Docker的MySQL8镜像, 实行数据持久化 使用Docker的MySQL8.0.17实例化一个容器之后需要对其进行数据持久化操作, 使用 docker docker run -p 7797:33 ...