详解 通道 (Channel 接口)

摘要:
在这篇博文中,我将主要解释NIO的两个核心点——缓冲区和其中一个通道的缓冲区。有关NIO流的其他知识点,请观看我的博客文章“NIO流详细信息”@Directory Channel FileChannel Class:分散和聚合:频道概述:来自java。nio由channels包定义。通道表示IO源和目标之间的开放连接。渠道类似于传统的“流动”。然而,通道本身不能直接访问数据,通道只能与缓冲区交互!StaticSeekableByteChannelnewByteChannel打开或创建一个文件并返回一个可寻址的字节通道以访问文件方法3:打开并通过通道接口的静态Open()方法返回指定的通道。

在本篇博文中,本人主要讲解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 extends OpenOption> 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 接口)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇plsql 建表空间git 生成patch 和打入patch下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

搞懂iobuffer就得先学习bytebuffer

ByteBuffer前前后后看过好几次了,实际使用也用了一些,总觉得条理不够清晰。 《程序员的思维修炼》一本书讲过,主动学习,要比单纯看资料效果来的好,所以干脆写个详细点的文章来记录一下。 概述 ByteBuffer是NIO里用得最多的Buffer,它包含两个实现方式:HeapByteBuffer是基于Java堆的实现,而DirectByteBuffer则...

Android OpenGL ES(七)基本几何图形定义 .

在前面Android OpenGL ES(六):创建实例应用OpenGLDemos程序框架我们创建了示例程序的基本框架,并提供了一个“Hello World”示例,将屏幕显示为红色。 本例介绍OpenGL ES 3D图形库支持的几种基本几何图形,通常二维图形库可以绘制点,线,多边形,圆弧,路径等等。OpenGL ES 支持绘制的基本几何图形分为三类:点,线...

Java NIO 学习笔记

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/SJQ。 http://www.cnblogs.com/shijiaqi1066/p/3344148.html 0 概述 0.1 Socket的问题 传统socket由于需要等待资源,所以会出现阻塞现象。服务器端一般只能使用一个客户端socket对应一个处理线程。 但是...

SocketChannel简述

前言 在前面的Channel概述的分类中提到过SocketChannel主要是用来基于TCP通信的通道。这篇文章详细介绍下SocketChannel SocketChannel是什么 SocketChannel特点 SocketChannel的使用 SocketChannel A selectable channel for stream-orient...

多渠道打包工具Walle源码分析

一、背景 首先了解多渠道打包工具Walle之前,我们需要先明确一个概念,什么是渠道包。 我们要知道在国内有无数大大小小的APP Store,每一个APP Store就是一个渠道。当我们把APP上传到APP Store上的时候,我们如何知道用户在那个渠道下载我们的APP呢?如果单凭渠道供应商自己给的话,那无疑会带来不可知的损失,当然除了这个原因,我们还有别的...

缓冲器的学习

导语 缓冲器的设计的是新IO模型中最基础的一部分。因为新IO模型中要求所有的IO操作都需要进行缓冲。在新的IO模型中,不再向输出流写入数据和从数据流中读取数据了,而是要从缓冲区中读写数据。缓冲区可是是数组,也可以是与硬件或内存直接连接。 从编程的角度来看,流和通道之间的关键区别子在于流是基于字节的,而通道是基于块的。流设计为按顺序一字节接一字节地传输数据。...