java nio 缓冲区(一)

  本文来自于我的个人博客:java nio 缓冲区(一)

我们以Buffer类开始对java.nio包的浏览历程。这些类是java.nio的构造基础。这个系列中,我们将跟随《java NIO》书籍一起深入研究缓冲区,了解各种不同的类型,并学会怎样使用。

一个Buffer对象是固定数量的数据容器。其作用是一个存储器,或者分段运输区,在这里数据可被存储并在之后用于检索。

Buffer类的家谱:

一,缓冲区基础

1.缓冲区的属性:

容量(capacity):缓冲区能够容纳的数据元素的最大数量,这一容量是在缓冲区被创建时设置的,并且永远不能被改变

上界(limit): 缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。

位置(position): 下一个要被读或写的元素的索引,位置会自动由相应的get()和put()函数更新。

标记(mark): 一个备忘位置,调用mark()来设定mark=position.调用reset()设定position=mark。标记在设定前是未定义的(undefied)。

这四个属性的关系如下:

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

接下来,我们看看这些属性在实际应用中的一些例子:

创建一个新的ByteBuffer,则缓冲区的各个属性状态如下图所示:

位置被设置为0,而且容量和上界被设为10,刚好经过缓冲区能够容纳的最后一个字节。标记最初未定义,容量是固定的,但另外三个属性可以在使用缓冲区时改变。

2.缓冲区API

让我们来看看如果使用一个缓冲区,以下是Buffer类的方法:

package java.nio;
public abstract class Buffer {
    public final int capacity();
    public final int position();
    public final Buffer position(int newPosition);
    public final int limit();
    public final Buffer limit(int newLimit);
    public final Buffer mark();
    public final Buffer reset();
    public final Buffer flip();
    public final Buffer rewind();
    public final int remaining();
    public final boolean hasRemaining();
    public abstract boolean isReadOnly();
}

关于这个API,有一点要注意,像clear()这类方法,通常应当返回void,而不是Buffer引用,这些函数将引用返回到它们在(this)上被引用的对象,这是一个允许级联调用的类设计方法。级联调用允许这种类型的代码:

buffer.mark();

buffer.position(5);

buffer.reset();

被简写为:buffer.mark().position(5).reset();

3.存取

我们将代表"Hello"字符串的ASCII码载入一个名为buffer的ByteBuffer对象中,缓冲区的结果状态如下图所示:

buffer.put((byte)‘H‘).put((byte)‘e‘).put((byte)‘1‘).put((byte)‘1‘).put((byte)‘o‘);

既然已经在buffer中存放了一些数据,如果我们想在不丢失位置的情况下进行一些更改该怎么办呢?put()的绝对方案可以达到这样的目的。假设我们想将缓冲区中的内容从"Hello"的ASCII码更改为"Mellow"。我们可以这样实现:

buffer.put(0,(byte)‘M‘).put((byte)‘w‘);修改后的buffer如下图所示:

4.翻转

在我们写满了缓冲区之后,现在我们必须准备将其清空。我们想把这个缓冲区传递给一个通道,以使内容能被全部写出,但如果通道现在在缓冲区上执行get(),那么它将从我们刚刚插入的游泳数据之外取出未定义的数据,如果我们将位置设置为0,通道就会从正确位置开始获取,但是它使怎样知道何时叨叨我们所插入数据末端的呢?这就是上界属性被引入的目的。buffer.limit(buffer.position()).position(0),但是这种从填充到释放转台的缓冲区翻转是预先设计好的,设计者为我们提供了更便利的方法buffer.flip(),flip方法将一个能够继续添加数据元素的填充状态的缓冲区饭庄成一个准备读出元素的释放状态,在翻转之后,缓冲区的状态如下图所示:

rewind()方法与flip()方法相似,但是它会改变limit的值,只是将position的值设置为0,这个方法可以用于回退已经度过的数据以便重新读取已经读过的数据。

方法hasRemaining会告诉你,是否已经达到缓冲区的上界,即limit-position=0,以下是一种将数据元素从缓冲区释放到一个数组的方法:

for(int i = 0; buffer.hasRemaining();i++{

byteArray[i] = buffer.get();

}

还有一种选择是使用remainig()方法,这个方法告诉你还剩余多少元素数目可被存入,可以根据以下方法释放缓冲:

int count = buffre.remaining();

for(int i = 0; i < count;i++) {

byteArray[i] = buffer.get();

}

5.下面是一个例子来填充以及释放缓冲区:

import java.nio.CharBuffer;
public class BufferFillDrain{
    private static int index = 0;
    private static String[] strings = {
        "hello word",
        "java is very beautiful",
        "python is very brief"
    };
    public static void main(String[] args) throws Exception{
        CharBuffer buffer = CharBuffer.allocate(100);
        while(fillBuffer(buffer)) {
            buffer.flip();
            drainBuffer(buffer);
            buffer.clear();
        }
    }
    
    private static void drainBuffer(CharBuffer buffer) {
        while(buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }
    }
    
    private static boolean fillBuffer(CharBuffer buffer) {
        if(index >= strings.length) {
            String string = strings[length];
            for(int i = 0; i < strings.length(); i++) {
                buffer.put(string.charAt(i));
            }
        }
        return true;
    }
}

6.压缩

有时,我们可能只想从缓冲区中释放一部分数据,而不是全部,然后重新填充,为了实现这一点,未读的数据元素需要下移以使第一个元素索引为0,而API对此提供了一个compact()方法,在释放缓冲区以前,可能有个缓冲区如下所示:

调用buffer.compact()方法之后,缓冲区的状态如下图所示:

可以看到,已经将释放的字节剔除,然后position的位置将会变为limit - originPosition,limit则被设置为limit=capacity。然后又重新从position位置填充数据。

7.缓冲区的比较

两个被认为是相同缓冲区的条件是从position位置开始到limit位置结束,这段字节之内的数据相同,则说明两个缓冲区相同,比较方法为buffer.compareTo(buffer),如下图所示两个缓冲区相同:

java nio 缓冲区(一),布布扣,bubuko.com

时间: 2025-01-31 09:39:23

java nio 缓冲区(一)的相关文章

Java NIO 缓冲区学习笔记

Buffer其实就是是一个容器对象,它包含一些要写入或者刚读出的数据.在NIO中加入Buffer对象,体现了新库与原I/O的一个重要区别.在面向流的I/O中,您将数据直接写入或者将数据直接读到Stream对象中. 在NIO库中,所有数据都是用缓冲区处理的.在读取数据时,它是直接读到缓冲区中的.在写入数据时,它是写入到缓冲区中的.任何时候访问NIO中的数据,您都是将它放到缓冲区中. 缓冲区实质上是一个数组.通常它是一个字节数组,但是也可以使用其他种类的数组.但是一个缓冲区不仅仅是一个数组.缓冲区提

java nio 缓冲区(二)

本文章来自于本人个人博客:java nio 缓冲区(二) 一,创建缓冲区 1.缓冲区的创建有两种方式,分别是ByteBuffer.allocate([int])或者ByteBuffer.wrap(byte[]),第一种方式是创建一个分配了int个字节的缓冲区,而第二种方式是在现有字节数组之上创建一个缓冲区,这个缓冲区的capacity就是数组的长度. 2.Buffer类的其它子类创建缓冲区也是一样的:CharBuffer.allocate(int)或者CharBuffer.wrap(byte[]

Java NIO -- 缓冲区(Buffer)的数据存取

缓冲区(Buffer): 一个用于特定基本数据类型的容器.由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类.Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的. Buffer 就像一个数组,可以保存多个相同类型的数据.根据数据类型不同(boolean 除外) ,有以下 Buffer 常用子类:ByteBufferCharBuffer ShortBuffer IntBuffer LongBuffer Flo

Java NIO 缓冲区

Java NIO 在JDK1.4的时候引入,主要解决传统IO的一些性能问题.NIO 主要内容包含 Buffer .Channel.Selector等内容,本文主要讲解Buffer相关的内容. Buffer的继承体系 Buffer的子类比较多,但是继承关系比较简单.8种基本类型,除了布尔类型,其余的类型都有对应的Buffer实现,名字也十分好记:基本数据类型首字母大写+Buffer.其中ByteBuffer最为常用,因为字节是操作系统及其I/O设备使用的基本数据类型,后面演示的时候也主要使用字节缓

Java-杂项-java.nio:java.nio

ylbtech-Java-杂项-java.nio:java.nio java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络. 1.返回顶部 1. 中文名:java非阻塞式IO 外文名:java nio 缓冲区:数据容器 特    性:Channel,Buffer,Selector 简    称:nio 目    的:提供非阻

Java NIO中的缓冲区Buffer(一)缓冲区基础

什么是缓冲区(Buffer) 定义 简单地说就是一块存储区域,哈哈哈,可能太简单了,或者可以换种说法,从代码的角度来讲(可以查看JDK中Buffer.ByteBuffer.DoubleBuffer等的源码),Buffer类内部其实就是一个基本数据类型的数组,以及对这个缓冲数组的各种操作: 常见的缓冲区如ByteBuffer.IntBuffer.DoubleBuffer...内部对应的数组依次是byte.int.double... 与通道的关系 在Java NIO中,缓冲区主要是跟通道(Chann

Java NIO (二) 缓冲区(Buffer)

缓冲区(Buffer):一个用于特定基本数据类型的容器,由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的Buffer 主要用于和NIO中的通道(Channel)进行交互, 数据从通道(Channel)读入缓冲区(Buffer)或者从缓冲区(Buffer)写入通道(Channel).如下,我画的一个简图,Chanenl直接和数据源或者目的位置接触,Buffer作为中介这,从一个Channel中读取数据,然后将数据写入另一个Channel中. Bu

java NIO 直接与非直接缓冲区

ByteBuffer有两个创建缓冲区的方法:static ByteBuffer allocate(int capacity)static ByteBuffer allocateDirect(int capacity) 这两个方法都是创建缓冲区的方法,使用直接缓冲区的时候,JVM虚拟机会直接在此缓冲区上执行本机IO操作,也就是说,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容). 直接字节缓冲区使用上边方法中的allocat

Java nio 笔记:系统IO、缓冲区、流IO、socket通道

一.Java IO 和 系统 IO 不匹配 在大多数情况下,Java 应用程序并非真的受着 I/O 的束缚.操作系统并非不能快速传送数据,让 Java 有事可做:相反,是 JVM 自身在 I/O 方面效率欠佳.操作系统与 Java 基于流的 I/O模型有些不匹配.操作系统要移动的是大块数据(缓冲区),这往往是在硬件直接存储器存取(DMA)的协助下完成的.而 JVM 的 I/O 操作类喜欢操作小块数据--单个字节.几行文本.结果,操作系统送来整缓冲区的数据,java.io 包的流数据类再花大量时间