java NIO 直接与非直接缓冲区

时间:2022-12-29 07:27:19

ByteBuffer有两个创建缓冲区的方法:
static ByteBuffer allocate(int capacity)
static ByteBuffer allocateDirect(int capacity)
  这两个方法都是创建缓冲区的方法,使用直接缓冲区的时候,JVM虚拟机会直接在此缓冲区上执行本机IO操作,也就是说,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容)。 直接字节缓冲区使用上边方法中的allocateDirect工厂方法创建,此方法返回的缓冲区进行分配和取消分配所需要的成本往往比间接缓冲区要高,直接缓冲区的内容可以驻留 在常规的垃圾回收堆之外,因此,它们对应用程序的内容需求量造成的影响可能并不明显,所以建议将直接缓冲区主要分配给那些容易受基础系统的本 机IO操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处的时候分配它们。
  直接缓冲区还可以使用mapping 将文件区域直接映射到内存中来创建,Java平台的实现有助于通过JNI从本机代码直接创建字节缓冲区,如果以上这些缓冲区中的某个缓冲区实例指的是不可 访问的内存区域,则视图访问该区域不会更改该缓冲区的内容,并且会在访问期间或稍候的某个时间导致抛出不确定的异常。
  字节缓冲区是直接缓冲区还是非直接缓 冲区可以通过ByteBuffer的isDirect方法来确定,提供该方法是为了能够在性能关键型代码中执行显示缓冲区管理。
  访问二进制数据:
  此类定义除了boolean之外,读写所有其他基本类型值的方法,这些基本值可 以根据缓冲区的当前字节顺序与字节序列相互进行转换,并可以通过order方法获取和修改。特定的字节顺序由ByteOrder类的实例进行表示,字节缓 冲区的初始顺序是BIG_ENDIAN(该顺序可以参考《Java内存模型》http://blog.csdn.net/silentbalanceyh/archive/2009/10/13/4661230.aspx)的。为了访问异类二进制数据,此类还针对每种类型定义了一系列绝对和相对的put和get方法, 并针对float、 char、short、int、long和double等类型定义了相对方法,该方法可以自行参考API内容。绝对get和put方法的 index参数是根据字节定义的,而不是根据所读写的类型定义的。
  为了访问同类二进制数据(即相同类型的值序列),此类还定义了可 以为指定类型的缓冲区创建视图的方法,视图缓冲区只是其内容受该字节缓冲区支持的另一种缓冲区,字节缓冲区内容的更改在视图缓冲区中是可见的,反之亦然;这两种缓冲区的位置、限制和标记 值都是独立的。使用视图缓冲区有三大优势:
视 图缓冲区不是根据字节进行索引,而是根据其特定于类型的值的大小进行索引
视 图缓冲区提供了相对批量put和get方法,这些方法可在缓冲区和数组或相同类型的其他缓冲区之间传输值的连续序列
视图缓冲区可能更高效,这是因为,当且仅当其支持的字节缓冲区为直接缓冲区时它才是直接缓冲区。
  实际上ByteBuffer是继承于Buffer类,里面存放的是字节,如果要 将它们转换成字符串则需要使用Charset,Charset是字符编码,它提供了把字节流转换成为字符流(解码)和 将字符串转换成字节流(编码)的方法。该类有一下三个重要的属性:
容量(capacity):表示该缓冲区可以存放多少数据
极限(limit):表示读写缓存的位置, 不能对超过位置进行数据的读或写操作
位置(position):表示下一个缓冲区的读写单元, 每读写一次缓存区,位置都会变化,位置是一个非负整数

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
  
public class QuickCopy {
    public static void main(String args[]) throws Exception{
        FileInputStream fin = new FileInputStream("D:/work/test.txt");
        FileOutputStream fout = new FileOutputStream("D:/work/output.txt");
        FileChannel inChannel = fin.getChannel();
        FileChannel outChannel = fout.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(true){
            int ret = inChannel.read(buffer);
            if( ret == -1)
                break;
            buffer.flip(); //该方法为父类Buffer的方法
            outChannel.write(buffer);
            buffer.clear(); //该方法为父类Buffer的方法
        }
    }
}

  上边的代码分配了1024个字节的直接缓冲区,然后使用本地拷贝的方式进行文件拷贝,应该是比 普通的文件拷贝更高效,这里解释几个比较常用的ByteBuffer类里面的方法【这里不介绍分配缓冲区的方法 了】:
public abstract ByteBuffer compact() throws ReadOnlyBufferException:
——该方法压缩此缓冲区(可选的),将缓冲区的当前位置和界限之间的字节复制到缓冲区的开始处,即将索引p = position()处 的字节复制到索引0处,将索引n+1处的字节复制到索引1的 位置,依次类推直到索引limit() - 1处的字节复制到索引 n = limit() - 1 - p处, 然后将缓冲区的位置设置为n + 1,并将其界限设置为其容量,如果已定义了标记,则丢弃。将缓冲区的位置设置为复制的字节数,而不是零,以便调 用此方法后可以紧接着调用另一个相对put方法。
public abstract ByteBuffer duplicate():
——创建共享此缓冲区内容的新的字节缓冲区,新缓冲区的内容将为此缓冲区的内容,此缓冲区内容的更改在新缓冲 区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。新缓冲区的容量、界限、位置和标记值将与此缓冲区相同。当且 仅当此缓冲区为直接时,新缓冲区才是直接的,当切仅当此缓冲区是只读时,新缓冲区才是只读的。
public abstract ByteBuffer slice():
——创建新的字节缓冲区,其内容是此缓冲区的共享子序列,新缓冲区的内容将从此缓冲区的当前位置开始,此缓冲 区内容的更改在新缓冲区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。
public abstract ByteBuffer wrap(byte[] array):
——将byte数组包装到缓冲区中,新的缓冲区将由给定的byte数组支持,也就是说,缓冲区修改 将导致数组修改,反之亦然。新缓冲区的容量和界限将为array.length,其位置将为零,其标记是不确定的,其底层实现数据将为给定数组,并且其数 组偏移量将为零。
  这里再提供几个基本操作的例子:

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
 
public class BasicType {
    public static void main(String args[]) throws Exception{
        // 使用字节数组创建ByteBuffer
        byte[] bytes = new byte[10];
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        // 创建字符ByteBuffer
        ByteBuffer charBuffer = ByteBuffer.allocate(15);
        CharBuffer charBuffer2 = buffer.asCharBuffer();
        // 设置获取字符类型的Buffer
        ByteBuffer charBuffer3 = ByteBuffer.allocate(100);
        charBuffer3.putChar((char)123);
        charBuffer3.flip();
        char c = charBuffer3.getChar();
    }
}

  上边是针对基本类型的操作,查阅API可以看到基本操作相关的类里面提供的方法

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
 
public class StringByteBuffer {
    public static void main(String args[]) throws Exception{
        // 使用ByteBuffer存储字符串
        ByteBuffer buffer = ByteBuffer.allocate(100);
        CharBuffer cBuffer = buffer.asCharBuffer();
        cBuffer.put("Hello World");
        cBuffer.flip();
        String result = cBuffer.toString();
    }
} 2013-01-13 名品推荐:潮顺品 榕宜 灵澜

java NIO 直接与非直接缓冲区的更多相关文章

  1. Java NIO -- 阻塞和非阻塞

    传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信进行 IO操作 ...

  2. Java NIO: Non-blocking Server 非阻塞网络服务器

    本文翻译自 Jakob Jenkov 的 Java NIO: Non-blocking Server ,原文地址:http://tutorials.jenkov.com/java-nio/non-bl ...

  3. Java NIO(二)缓冲区

    概念 缓冲区:一个用于特定基本数据类型的容器,由java.nio包定义的所有缓冲区都是Buffer抽象类的子类.其作用于与NIO的通道进行交互,数据从通道读入缓冲区,数据从缓冲区写入通道 Buffer ...

  4. Java NIO ———— Buffer 缓冲区详解 入门

    引言缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存入 ...

  5. Java NIO入门(二):缓冲区内部细节

    Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...

  6. Java NIO 之 Buffer(缓冲区)

    一 Buffer(缓冲区)介绍 Java NIO Buffers用于和NIO Channel交互. 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels. Bu ...

  7. java nio使用方法(转)

    最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下 ...

  8. Java NIO学习笔记一 Java NIO概述

    Java NIO概述 Java NIO(新的IO)是Java的替代IO API(来自Java 1.4),这意味着替代标准的 java IO和java Networking API.Java NIO提供 ...

  9. Java NIO 概览

    Java面试通关手册(Java学习指南) Github地址:https://github.com/Snailclimb/Java_Guide 一 NIO简介 Java NIO 是 java 1.4 之 ...

随机推荐

  1. Pipe

    #一边压缩一边传 一边解压 到对方的目录为/tlj/2/ / | ssh root@172.16.200.56 tar xzf - -C /tlj #在一个需要文件名的地方 使用-重定向输出到stdo ...

  2. 修改Widows网络设置提升网速

    可能很多用户不知道,我们在使用Windows系统连接Internet,系统默认保留20%的带宽,也就是说我们进行网络数据传输所能使用的带框仅为实际带宽的80%,但是我们修改网络设置或的最大带宽. 1. ...

  3. javascript删除数组里的对象

    Array.prototype.del = function(value) { //删除数组中指定的元素,返回新数组 function hasValue(array, value) { for(var ...

  4. js:深闭包(范围:上)

    /**  * 范围*  */ fn1(); //fn1 您可以运行,没有报错,对于由function func_name()这样的写法来定义的函数,永远都会被最先初始化. function fn1( ...

  5. 初始Oracle

    1.Oracle简介 Oracle体系结构: 先是用户进程发起一个请求到服务器进程(PGA  ,  一个PGA对应一个请求),然后PGA在发送给SGA.SGA有三大块分别是:共享池,数据缓冲区,日志缓 ...

  6. Cloudera Manager和CDH5.8离线安装

    https://blog.csdn.net/zzq900503/article/details/52982828 简介 我们在上篇文章中已经了解了CDH,为了后续的学习,我们本章就来安装CDH5.8. ...

  7. Docker 更改默认存储目录 - 十一

    Cemtos 7 Docker 默认目录是 /var/lib/docker docker info 查看 docker 配置信息 更改 docker 默认目录 :  编辑 启动文件: 编辑 /usr/ ...

  8. 利用UML语言建模--以图书馆管理系统为例

    一.基本信息 标题:利用UML语言建模--以图书馆管理系统为例 时间:2016 出版源:内蒙古科技与经济 领域分类:UML:RFID:图书馆:模型: 二.研究背景 问题定义:建立图书馆管理系统 难点: ...

  9. centos6.5 手动安装gcc

    gcc版本:gcc-4.4.7 rpm -Uvh  mpfr-2.4.1-6.el6.x86_64.rpm rpm -Uvh  cpp-4.4.7-16.el6.x86_64.rpmrpm -Uvh  ...

  10. KMP与AC自动机

    KMP算法主要思想就是预处理出失配函数, 从而减少匹配失败时的回溯, 复杂度是$\Theta(m+n)$, 已达到理论下界 c++代码如下 int n, f[N]; char t[N], p[N]; ...