资讯专栏INFORMATION COLUMN

JAVA_NIO系列——Channel和Buffer详解

leon / 2393人阅读

摘要:是一个用来替代标准的新型数据传递方式,像现在分布式架构中会经常存在他的身影。这个方法会一直阻塞到某个注册的通道有事件就绪。保持不变,仍然表示能从中读取多少个元素等与通过调用方法,可以标记中的一个特定。

Java NIO是一个用来替代标准Java IO API的新型数据传递方式,像现在分布式架构中会经常存在他的身影。其比传统的IO更加高效,非阻塞,异步,双向

NIO主体结构

Java NIO的主要构成核心就是Buffer、Channel和Selector这三个

对于Channel我想要提醒的是,Channel中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入

使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件

Channel

所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流

Channel的实现

FileChannel:从文件中读写数据

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

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

ServerSocketChannel:监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel

Scatter/Gather

分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中

聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel

通过这样的方式可以方便数据的读取,当你想要获取整个数据的一部分的时候,通过这种方式可以很快的获取数据

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);

read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写

transferFrom、transferTo

实现两个Channel之间相互连接,数据传递

    public static void trainforNio() {
        RandomAccessFile fromFile=null;
        RandomAccessFile toFile=null;
        try {

            fromFile = new RandomAccessFile("src/nio.txt", "rw");
            // channel获取数据
            FileChannel fromChannel = fromFile.getChannel();
            toFile = new RandomAccessFile("src/toFile.txt", "rw");
            FileChannel toChannel = toFile.getChannel();
            System.out.println(toChannel.size());
              //position处开始向目标文件写入数据,这里是toChannel
            long position = toChannel.size();
            long count = fromChannel.size();
            toChannel.transferFrom(fromChannel, position, count);
            System.out.println(toChannel.size());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fromFile != null) {
                    fromFile.close();
                }
                if (toFile != null) {
                    toFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

transferFrom、transferTo作用是一样的,只是一个是tochannal调用,一个是fromchannnal调用

在实际的运用中可能存在源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数

在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中

看官一定要仔细看我栗子中的注释

Buffer

Buffer是一个缓存区,其会将Channel中的数据存储起来

Buffer的实现

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

MappedByteBuffer

capacity,position,limit

在讲解该主题之前,首先要明白读模式和写模式,无论是Channel还是Buffer都存在这两种模式,要理解这两种模式,第一步要明确主题是哪一个,是Channel还是Buffer。举个栗子,主角是Channel,读模式的含义就是从Buffer中获取数据,写模式就是将数据写入Buffer,对于Buffer则是相反。搞清楚这一点,理解下面的就要相对清楚一点

capacity:作为一个内存块,其就代表了当前Buffer能最多暂存多少数据量,存储的数据类型则是根据上面的Buffer对象类型,一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据

position:代表当前数据读或写处于那个位置。读模式:被重置从0开始,最大值可能为capacity-1或者limit-1,写模式:被重置从0开始,最大值为limit-1

limit:最多能往Buffer里写多少数据,limit大小跟数据量大小和capacity有关,读模式:数据量>capacity时,limit=capacity,数据量=capacity时,limit=capacity,数据量

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Method {
    public static void nio() {
        RandomAccessFile aFile = null;
        try {

            aFile = new RandomAccessFile("src/nio.txt", "rw");
            // channel获取数据
            FileChannel fileChannel = aFile.getChannel();
            // 初始化Buffer,设定Buffer每次可以存储数据量
            // 创建的Buffer是1024byte的,如果实际数据本身就小于1024,那么limit就是实际数据大小
            ByteBuffer buf = ByteBuffer.allocate(1024);
            // channel中的数据写入Buffer
            int bytesRead = fileChannel.read(buf);
            System.out.println(bytesRead);

            while (bytesRead != -1) {
                // Buffer切换为读取模式
                buf.flip();
                // 读取数据
                while (buf.hasRemaining()) {
                    System.out.print((char) buf.get());
                }
                // 清空Buffer区
                buf.compact();
                // 继续将数据写入缓存区
                bytesRead = fileChannel.read(buf);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (aFile != null) {
                    aFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        Method.nio();
    
Buffer读写数据步骤

写入数据到Buffer(fileChannel.read(buf))

调用flip()方法(buf.flip())

从Buffer中读取数据(buf.get())

调用clear()方法或者compact()方法(buf.compact())

Buffer方法

flip():将Buffer读模式切换到写模式,并且将position制为0

clear():清空整个缓冲区

compact():只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面

allocate(1024):初始化Buffer,设定的值就决定capacity值的大小

rewind():将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)

mark()与reset():通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position

equals():当满足下面三个条件时,两个Buffer才是相等

有相同的类型(byte、char、int等)

Buffer中剩余的byte、char等的个数相等

Buffer中所有剩余的byte、char等都相同

只比较的是剩余的数据

compareTo():满足下列条件,则认为一个Buffer“小于”另一个Buffer

第一个不相等的元素小于另一个Buffer中对应的元素

所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)

Selector

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便

关于selector的知识内容比较多了,我打算在下一期进行详细说明

更多内容可以关注微信公众号,或者访问AppZone网站

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64799.html

相关文章

  • JAVA_NIO详细解析说明

    摘要:通道是和选择器一起被注册的,并且使用选择器来更新通道的就绪状态。注册不会立即被取消,但键会立即失效。这个集合的每个成员都是相关的通道被选择器在前一个选择操作中判断为已经准备好的,并且包 Java NIO是一个用来替代标准Java IO API的新型数据传递方式,像现在分布式架构中会经常存在他的身影。其比传统的IO更加高效,非阻塞,异步,双向 NIO主体结构 showImg(http:/...

    SillyMonkey 评论0 收藏0
  • JDK10都发布了,nio你了解多少?

    摘要:而我们现在都已经发布了,的都不知道,这有点说不过去了。而对一个的读写也会有响应的描述符,称为文件描述符,描述符就是一个数字,指向内核中的一个结构体文件路径,数据区等一些属性。 前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 本来我预想是先来回顾一下传统的IO模式的,将传统的IO模式的相关类理清楚(因为IO的类很多)。 但是,发现在整理的过程已...

    YFan 评论0 收藏0
  • Java NIO详解

    摘要:前言本篇主要讲解中的机制和网络通讯中处理高并发的分为两块第一块讲解多线程下的机制第二块讲解如何在机制下优化资源的浪费服务器单线程下的机制就不用我介绍了,不懂得可以去查阅下资料那么多线程下,如果进行套接字的使用呢我们使用最简单的服务器来帮助大 前言 本篇主要讲解Java中的IO机制和网络通讯中处理高并发的NIO 分为两块:第一块讲解多线程下的IO机制第二块讲解如何在IO机制下优化CPU资...

    rickchen 评论0 收藏0
  • Java NIO 之 Buffer(缓冲区)

    摘要:一缓冲区介绍用于和交互。的容量,位置,上限缓冲区实质上就是一块内存,用于写入数据,也供后续再次读取数据。在每个类中,方法用于分配缓冲区。没有这句话会报错将此缓冲区的位置重置为先前标记的位置。返回此缓冲区的限制。 一 Buffer(缓冲区)介绍 Java NIO Buffers用于和NIO Channel交互。 我们从Channel中读取数据到buffers里,从Buffer把数据写入到...

    gitmilk 评论0 收藏0
  • Java NIO 的前生今世 之三 NIO Buffer 详解

    摘要:当我们需要与进行交互时我们就需要使用到即数据从读取到中并且从中写入到中实际上一个其实就是一块内存区域我们可以在这个内存区域中进行数据的读写其实是这样的内存块的一个封装并提供了一些操作方法让我们能够方便地进行数据的读写类型有这些覆盖了能从中传 Java NIO Buffer 当我们需要与 NIO Channel 进行交互时, 我们就需要使用到 NIO Buffer, 即数据从 Buffe...

    madthumb 评论0 收藏0

发表评论

0条评论

leon

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<