ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java NIO 中 Buffer 和 Channel 的简单介绍

2021-09-10 18:34:43  阅读:178  来源: 互联网

标签:capacity Java NIO Buffer System buffer limit position


在使用 BufferedReader 读取输入流中的数据时,如果没有读到有效数据,程序将在此出阻塞该线程的执行(使用 InputStream 的 read() 方法从流中读取数据时,如果数据流中没有数据,它也会阻塞该线程)。也就是说,传统的输入流、输出流都是阻塞式输入、输出。

从 JDK 1.4 开始,Java 提供了一系列新的IO(New IO,简称 NIO),位于 java.nio 包及子包下,并且对原 java.io 包中的很多类以 NIO 为基础进行了改写,新增了满足 NIO 的功能。

Channel(通道)和 Buffer(缓冲)是 NIO 中的两个核心对象。

Buffer

Buffer 可以被理解成一个容器,它的本质是一个数组。

Buffer 是一个抽象类,其最常用的子类是 ByteBuffer。除此之外,还有对应于其他基本数据(boolean除外)对应的 Buffer 类:CharBuffer、ShorBuffer......等。

在 Buffer 中有三个重要的概念:capacity(容量)、limit(界限)、position(位置)

  • capacity(容量):缓冲区的容量,创建后不可改变,不可能为负值。
  • limit(界限):limit 后的数据不可被读写。
  • position(位置):用于指明下一个可以被读出的或者写入的缓冲区位置索引。

此外,Buffer 里还支持一个可选标记(mark),这些值满足下列关系:

0 << mark << position << limit << capacity

如图:

Buffer 的主要作用是装入数据,然后输出数据。

开始时 Buffer 的 position 为 0,limit 为 capacity,程序可以通过 put() 方法向 Buffer 中放入数据,没放入一些数据,position 相应地向后移动一些位置。

当 Buffer 装入数据结束后,调用 Buffer 的 flip() 方法,该方法将limit 设置为 position 所在位置,并将 position 设为 0,这就使得 Buffer 的读写指针又回到了开始位置,之后 Buffer 为输出数据做好准备。(调用 get() 方法可输出数据)

当 Buffer 输出数据结束后,Buffer 可调用 clear() 方法,这个方法不是清空 Buffer 的数据,它仅仅是将 position 设置为0,将 limit设置为 capacity,这样为再次向 Buffer 装入数据做准备。但之前已有的数据还是在 Buffer 中,后面装数据时会将原来位置的数据覆盖。

import java.nio.CharBuffer;

public class BufferDemo2 {

    public static void main(String[] args) {
        CharBuffer buffer = CharBuffer.allocate(8);     //创建 Buffer 时指定 capacity为8
        //开始时 limit = capacity = 8, position = 0
        System.out.println("capacity: " + buffer.capacity() 
                           + ", limit: " + buffer.limit() 
                           + ", position: " + buffer.position());

        // 输入数据
        buffer.put('a');
        buffer.put('b');
        buffer.put('c');
        // capacity: 8, limit: 8, position: 3
        System.out.println("capacity: " + buffer.capacity() 
                           + ", limit: " + buffer.limit() 
                           + ", position: " + buffer.position());  

        buffer.flip();
        System.out.println("******* flip  **");
        // capacity: 8, limit: 3, position: 0
        System.out.println("capacity: " + buffer.capacity() 
                           + ", limit: " + buffer.limit() 
                           + ", position: " + buffer.position()); 

        // 输出数据,返回a
        System.out.println("1: " + buffer.get());
        // capacity: 8, limit: 3, position: 1
        System.out.println("capacity: " + buffer.capacity() 
                           + ", limit: " + buffer.limit() 
                           + ", position: " + buffer.position()); 

        System.out.println("******* clear  **");
        buffer.clear();
        // capacity: 8, limit: 8, position: 0
        System.out.println("capacity: " + buffer.capacity() 
                           + ", limit: " + buffer.limit() 
                           + ", position: " + buffer.position());  

        System.out.println("clear 后,第一个元素: " + buffer.get(0));  // a
        System.out.println("clear 后,第三个元素: " + buffer.get(2));  // c
        buffer.put('d');
        System.out.println("limit: " + buffer.limit());     // 8
        System.out.println("position: " + buffer.position());   // 1
        System.out.println("clear 后,第一个元素: " + buffer.get(0));  // d
        System.out.println("clear 后,第三个元素: " + buffer.get(2));  // c
    }
}

Channel

Channel 类似于传统的流对象,但也有两个主要区别。

  • Channel 可以直接将指定文件的部分或全部直接映射成 Buffer。
  • 程序不能直接访问 Channel 中的数据,包括读写都不行,Channel 只能与 Buffer 进行交互。

Java为 Channel 接口提供了 DatagramChannel、FileChannel、Pipe.SinkChannel,、Pipe.SourceChannel、 SelectableChannel,、ServerSocketChannel,、SocketChannel 等实现类。

其中, Pipe.SinkChannel,、Pipe.SourceChannel 是用于支持线程之间通信的管道 Channel ;ServerSocketChannel,、SocketChannel 是用于支持 TCP 网络通信的 Channel ;DatagramChannel 则是用于支持 UDP 网络通信的 DatagramChannel。

所有的 Channel 都不应该通过构造器来创建,而是通过传统的节点流 InputStram、OutputStream 的 getChannel() 方法来返回对应的 Channel ,不同节点流获得的 Channel 不一样。

例如,FileInputStream、FileOutputStream 的getChannel() 返回的是 FileChannel

Channel 中最常用的三类方法是 map()、read()、write(),其中:

map() 方法用于将 Channel 对应的部分或全部数据映射成 ByteBuffer;

read() 或 write() 方法都有一系列重载形式,这些方法用于从 Buffer 中读取或写入数据。

MappedByteBuffer map(FileChannel.MapMode mode,long position,long size) : 第一个参数执行映射时的模式,分别为只读、读写、专用 这3种模式;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
 * 将文件 object.txt 的内容复制到文件 b.txt 中,并在控制台输出
 */
public class FileChannelTest {
    public static void main(String[] args) {

        File f = new File("object.txt");
        try {
            //创建 FileInputStream,以该文件输入流创建 FileChannel
            FileChannel inChannel = new FileInputStream(f).getChannel();
            // 以文件输出流创建 FileChannel,用以控制输出
            FileChannel outChannel = new FileOutputStream("b.txt").getChannel();

            //将 inChannel 里的全部数据映射成 ByteBuffer
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            
            Charset charset = Charset.forName("GBK");
            // 直接将 buffer 里的数据全部输出
            outChannel.write(buffer);
            
            buffer.clear();
            // 创建解码器(CharsetDecoder)对象
            CharsetDecoder decoder = charset.newDecoder();
            // 使用解码器将 ByteBuffer 转换成 CharBuffer
            CharBuffer charBuffer = decoder.decode(buffer);
            // CharBuffer 的 toString 方法可以获取对应的字符串
            System.out.println(charBuffer);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

标签:capacity,Java,NIO,Buffer,System,buffer,limit,position
来源: https://www.cnblogs.com/luler/p/15252656.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有