`
cloudeagle_bupt
  • 浏览: 585217 次
文章分类
社区版块
存档分类
最新评论

java NIO 直接与非直接缓冲区

 
阅读更多

ByteBuffer有两个创建缓冲区的方法:

static<wbr></wbr>ByteBuffer allocate(int<wbr></wbr>capacity)
static<wbr></wbr>ByteBuffer allocateDirect(int<wbr></wbr>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)的。为了访问异类二进制数据,此类还针对每种类型定义了一系列绝对和相对的putget方法, 并针对float、 char、short、int、longdouble等类型定义了相对方法,该方法可以自行参考API内容。绝对get和put方法的 index参数是根据字节定义的,而不是根据所读写的类型定义的。
  为了访问同类二进制数据(即相同类型的值序列),此类还定义了可 以为指定类型的缓冲区创建视图的方法,视图缓冲区只是其内容受该字节缓冲区支持的另一种缓冲区,字节缓冲区内容的更改在视图缓冲区中是可见的,反之亦然;这两种缓冲区的位置、限制和标记 值都是独立的。使用视图缓冲区有三大优势:
  • 视 图缓冲区不是根据字节进行索引,而是根据其特定于类型的值的大小进行索引
  • 视 图缓冲区提供了相对批量put和get方法,这些方法可在缓冲区和数组或相同类型的其他缓冲区之间传输值的连续序列
  • 视图缓冲区可能更高效,这是因为,当且仅当其支持的字节缓冲区为直接缓冲区时它才是直接缓冲区。
  实际上ByteBuffer是继承于Buffer类,里面存放的是字节,如果要 将它们转换成字符串则需要使用Charset,Charset是字符编码,它提供了把字节流转换成为字符流(解码)和 将字符串转换成字节流(编码)的方法。该类有一下三个重要的属性:
  • 容量(capacity):表示该缓冲区可以存放多少数据
  • 极限(limit):表示读写缓存的位置, 不能对超过位置进行数据的读或写操作
  • 位置(position):表示下一个缓冲区的读写单元, 每读写一次缓存区,位置都会变化,位置是一个非负整数
  ——[$]快速复制文件——
package<wbr></wbr>org.susan.java.io;

import<wbr></wbr>java.io.FileInputStream;
import<wbr></wbr>java.io.FileOutputStream;
import<wbr></wbr>java.nio.ByteBuffer;
import<wbr></wbr>java.nio.channels.FileChannel;

public class<wbr></wbr>QuickCopy {
<wbr><wbr><span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal"><wbr>public static void</wbr></span><span style="word-wrap:normal; word-break:normal"><wbr></wbr></span>main(<span style="word-wrap:normal; word-break:normal">String<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>args[])<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">throws<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>Exception{</wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>FileInputStream fin =<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">new<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>FileInputStream(<span style="word-wrap:normal; word-break:normal">"D:/work/test.txt"</span>);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>FileOutputStream fout =<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">new<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>FileOutputStream(<span style="word-wrap:normal; word-break:normal">"D:/work/output.txt"</span>);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>FileChannel inChannel = fin.getChannel();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>FileChannel outChannel = fout.getChannel();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>ByteBuffer buffer = ByteBuffer.<em><span style="word-wrap:normal; word-break:normal">allocate</span></em>(<span style="word-wrap:normal; word-break:normal">1024</span>);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">while</span>(<span style="word-wrap:normal; word-break:normal">true</span>){</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">int<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>ret = inChannel.read(buffer);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">if</span>( ret == -1)</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">break</span>;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>buffer.flip();<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">//该方法为父类Buffer的方法</span></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>outChannel.write(buffer);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>buffer.clear();<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">//该方法为父类Buffer的方法</span></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>}</wbr></wbr></wbr>
}
  上边的代码分配了1024个字节的直接缓冲区,然后使用本地拷贝的方式进行文件拷贝,应该是比 普通的文件拷贝更高效,这里解释几个比较常用的ByteBuffer类里面的方法【这里不介绍分配缓冲区的方法 了】:
public abstract<wbr></wbr>ByteBuffer compact()<wbr></wbr>throws<wbr></wbr>ReadOnlyBufferException:
——该方法压缩此缓冲区(可选的),将缓冲区的当前位置和界限之间的字节复制到缓冲区的开始处,即将索引p = position()处 的字节复制到索引0处,将索引n+1处的字节复制到索引1的 位置,依次类推直到索引limit() - 1处的字节复制到索引<wbr></wbr>n = limit() - 1 - p处, 然后将缓冲区的位置设置为n + 1,并将其界限设置为其容量,如果已定义了标记,则丢弃。将缓冲区的位置设置为复制的字节数,而不是零,以便调 用此方法后可以紧接着调用另一个相对put方法。
public abstract<wbr></wbr>ByteBuffer duplicate():
——创建共享此缓冲区内容的新的字节缓冲区,新缓冲区的内容将为此缓冲区的内容,此缓冲区内容的更改在新缓冲 区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。新缓冲区的容量、界限、位置和标记值将与此缓冲区相同。当且 仅当此缓冲区为直接时,新缓冲区才是直接的,当切仅当此缓冲区是只读时,新缓冲区才是只读的。
public abstract<wbr></wbr>ByteBuffer slice():
——创建新的字节缓冲区,其内容是此缓冲区的共享子序列,新缓冲区的内容将从此缓冲区的当前位置开始,此缓冲 区内容的更改在新缓冲区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。
public abstract<wbr></wbr>ByteBuffer wrap(byte[] array):
——将byte数组包装到缓冲区中,新的缓冲区将由给定的byte数组支持,也就是说,缓冲区修改 将导致数组修改,反之亦然。新缓冲区的容量和界限将为array.length,其位置将为零,其标记是不确定的,其底层实现数据将为给定数组,并且其数 组偏移量将为零。
  这里再提供几个基本操作的例子:
  ——[$]基本类型和ByteBuffer——
package<wbr></wbr>org.susan.java.io;

import<wbr></wbr>java.nio.ByteBuffer;
import<wbr></wbr>java.nio.CharBuffer;

public class<wbr></wbr>BasicType {
<wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">public static void</span><span style="word-wrap:normal; word-break:normal"><wbr></wbr></span>main(<span style="word-wrap:normal; word-break:normal">String<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>args[])<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">throws<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>Exception{</wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">// 使用字节数组创建ByteBuffer</span></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">byte</span>[] bytes =<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">new byte</span>[10];</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>ByteBuffer buffer = ByteBuffer.<em><span style="word-wrap:normal; word-break:normal">wrap</span></em>(bytes);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">// 创建字符ByteBuffer</span></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>ByteBuffer charBuffer = ByteBuffer.<em><span style="word-wrap:normal; word-break:normal">allocate</span></em>(15);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>CharBuffer charBuffer2 = buffer.asCharBuffer();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">// 设置获取字符类型的Buffer</span></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>ByteBuffer charBuffer3 = ByteBuffer.<em><span style="word-wrap:normal; word-break:normal">allocate</span></em>(100);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>charBuffer3.putChar((char)123);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>charBuffer3.flip();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>char c = charBuffer3.getChar();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>}</wbr></wbr></wbr>
}
  上边是针对基本类型的操作,查阅API可以看到基本操作相关的类里面提供的方法
  ——[$]String和ByteBuffer——
package<wbr></wbr>org.susan.java.io;

import<wbr></wbr>java.nio.ByteBuffer;
import<wbr></wbr>java.nio.CharBuffer;

public class<wbr></wbr>StringByteBuffer {
<wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">public static void<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>main(<span style="word-wrap:normal; word-break:normal">String<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>args[])<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span><span style="word-wrap:normal; word-break:normal">throws<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>Exception{</wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">// 使用ByteBuffer存储字符串</span></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>ByteBuffer buffer = ByteBuffer.<em><span style="word-wrap:normal; word-break:normal">allocate</span></em>(100);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>CharBuffer cBuffer = buffer.asCharBuffer();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>cBuffer.put(<span style="word-wrap:normal; word-break:normal">"Hello World"</span>);</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr>cBuffer.flip();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><span style="word-wrap:normal; word-break:normal">String<span style="word-wrap:normal; word-break:normal"><wbr></wbr></span></span>result = cBuffer.toString();</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>}</wbr></wbr></wbr>
}
分享到:
评论

相关推荐

    java NIO.zip

    NIO的核心在于通道(Channels)和缓冲区(Buffers)的概念,与传统的流(Streams)有所不同。 1. **通道(Channels)**: 通道是NIO中的核心概念之一,它提供了从一个数据源(如文件、套接字)到另一个数据源的...

    java NIO 视频教程

    Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。 Java NIO: Selectors(选择器) ...

    Java NIO英文高清原版

    2. **缓冲区(Buffer)**:在NIO中,数据被存储在缓冲区对象中。缓冲区提供了一种高效的方式管理内存,可以方便地进行读写操作。缓冲区有固定大小,一旦写满,需要清空或者翻转才能继续写入。同样,读取数据也需要将...

    Java NIO非阻塞服务端与客户端相互通信

    本教程将深入讲解如何使用Java NIO实现非阻塞服务端与客户端的通信。 1. **Java NIO基础** - **通道(Channels)**:NIO中的通道类似于传统IO的流,但它们可以同时读写,并且支持非阻塞操作。 - **缓冲区...

    java nio 读文件

    NIO的主要特点是面向缓冲区,非阻塞I/O,以及选择器,这些特性使得NIO在处理大量并发连接时表现出更高的效率。在本篇文章中,我们将深入探讨Java NIO如何读取文件。 一、NIO的基本概念 1. 缓冲区(Buffer):NIO的...

    java NIO技巧及原理

    Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 Blocking I/O(IO)相比,提供了更加高效的数据传输方式。在Java NIO中,"新"主要体现在非阻塞和多路复用这两个特性上,这使得NIO更适合于...

    JavaNIO.pdf

    Java NIO(Non-blocking I/O)是Java平台中的一种I/O处理方式,它提供了面向缓冲区的I/O处理机制,可以实现高性能、高效的I/O操作。 缓冲区(Buffer) 缓冲区是Java NIO中非常重要的一个概念,它是特定基本类型...

    Java NIO.pdf

    - **直接缓冲区**:通过 `allocateDirect()` 创建,数据直接存放在操作系统内核中,绕过 JVM 的堆,从而提高 I/O 效率。 - **间接缓冲区**:通常通过 `allocate()` 创建,数据存储在 JVM 的堆中。 #### 四、通道...

    java NIO实例

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效的数据传输方式。传统的Java I/O模型(BIO)在处理大量并发连接时效率较...

    一个java NIO的例子

    Java NIO提供了字节、字符、短整型、整型、长整型、浮点型和双精度浮点型等类型的缓冲区。缓冲区具有特定的方法,如put和get,用于数据的存取。 3. **选择器(Selector)**:选择器是Java NIO的核心,它可以监视多...

    java nio 包读取超大数据文件

    Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本中得到了进一步增强和完善。相较于传统的Java IO,NIO具有更高的性能和...

    Java NIO测试示例

    Java NIO提供了ByteBuf、CharBuf、ShortBuf、IntBuf、LongBuf、FloatBuf和DoubleBuf等不同类型的缓冲区,它们都有统一的API,如put()用于写入数据,get()用于读取数据,clear()用于清空缓冲区,flip()用于切换读写...

    JAVA NIO学习网站

    在Java传统IO中,数据的读写都是通过流来完成,而NIO则引入了通道(Channel)和缓冲区(Buffer)的概念,提供了一种非阻塞的I/O操作方式,极大地提高了Java进行并发I/O处理的能力。 首先,我们来看下NIO的核心组件...

    Java NIO 中英文版

    - Java NIO支持通道间的直接数据传输,例如可以从一个FileChannel直接将数据传输到SocketChannel,无需经过缓冲区,减少了数据复制的开销。 6. **异步I/O** - Java NIO还提供了异步I/O操作,通过...

Global site tag (gtag.js) - Google Analytics