内容目录
2.4.3 视图缓冲区
就像我们已经讨论的那样,I/O 基本上可以归结成组字节数据的四处传递。在进行大数据量的 I/O 操作时,很又可能您会使用各种ByteBuffer
类去读取文件内容,接收来自网络连接的数据,等等。一旦数据到达了您的 ByteBuffer
,您就需要查看它以决定怎么做或者在将它发送出去之前对它进行一些操作。ByteBuffer
类提供了丰富的 API 来创建视图缓冲区。
视图缓冲区通过已存在的缓冲区对象实例的工厂方法来创建。这种视图对象维护它自己的属性,容量,位置,上界和标记,但是和原来的缓冲区共享数据元素。我们已经在 2.3 节见过了这样的简单例子,在例子中一个缓冲区被复制和切分。但是ByteBuffer
类允许创建视图来将byte
型缓冲区字节数据映射为其它的原始数据类型。例如,asLongBuffer()
函数创建一个将八个字节型数据当成一个 long 型数据来存取的视图缓冲区。
下面列出的每一个工厂方法都在原有的ByteBuffer
对象上创建一个视图缓冲区。调用其中的任何一个方法都会创建对应的缓冲区类型,这个缓冲区是基础缓冲区的一个切分,由基础缓冲区的位置和上界决定。新的缓冲区的容量是字节缓冲区中存在的元素数量除以视图类型中组成一个数据类型的字节数(参见表 2-1)。在切分中任一个超过上界的元素对于这个视图缓冲区都是不可见的。视图缓冲区的第一个元素从创建它的ByteBuffer
对象的位置开始(positon()
函数的返回值)。具有能被自然数整除的数据元素个数的视图缓冲区是一种较好的实现。
public abstract class ByteBuffer extends Buffer implements Comparable
{
// 这里仅列出部分API
public abstract CharBuffer asCharBuffer();
public abstract ShortBuffer asShortBuffer();
public abstract IntBuffer asIntBuffer();
public abstract LongBuffer asLongBuffer();
public abstract FloatBuffer asFloatBuffer();
public abstract DoubleBuffer asDoubleBuffer();
}
下面的代码创建了一个ByteBuffer
缓冲区的CharBuffer
视图,如图 Figure 2-16所示(Example 2-2 将这个框架用到了更大的范围)
ByteBuffer byteBuffer = ByteBuffer.allocate (7).order(ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer();
例 2-2. 创建一个 ByteBuffer 的字符视图
package com.ronsoft.books.nio.buffers;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.ByteOrder;
/**
* Test asCharBuffer view.
*
* Created May 2002
* @author Ron Hitchens (ron@ronsoft.com)
*/
public class BufferCharView
{
public static void main (String [] argv) throws Exception
{
ByteBuffer byteBuffer = ByteBuffer.allocate(7).order (ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer( );
// Load the ByteBuffer with some bytes
byteBuffer.put (0, (byte)0);
byteBuffer.put (1, (byte)'H');
byteBuffer.put (2, (byte)0);
byteBuffer.put (3, (byte)'i');
byteBuffer.put (4, (byte)0);
byteBuffer.put (5, (byte)'!');
byteBuffer.put (6, (byte)0);
println (byteBuffer);
println (charBuffer);
}
// Print info about a buffer
private static void println (Buffer buffer)
{
System.out.println ("pos=" + buffer.position() + ", limit=" + buffer.limit() + ", capacity=" + buffer.capacity() + ": '" + buffer.toString() + "'");
}
}
运行BufferCharView程序的输出是:
pos=0, limit=7, capacity=7: 'java.nio.HeapByteBuffer[pos=0 lim=7 cap=7]'
pos=0, limit=3, capacity=3: 'Hi!
一旦您得到了视图缓冲区,您可以用duplicate()
, slice()
和asReadOnlyBuffer()
函数创建进一步的子视图,就像 2.3 节所讨论的那样。
无论何时一个视图缓冲区存取一个ByteBuffer
的基础字节,这些字节都会根据这个视图缓冲区的字节顺序设定被包装成一个数据元素。当一个视图缓冲区被创建时,视图创建的同时它也继承了基础ByteBuffer
对象的字节顺序设定。这个视图的字节排序不能再被修改。在图 2-16 中,您可以看到基础ByteBuffer
对象中的两个字节映射成CharBuffer
对象中的一个字符。字节顺序设定决定了这些字节对是怎么样被组合成字符型变量的。请参考2.4.1 节获取更多详细的解释。
当直接从byte
型缓冲区中采集数据时,视图换冲突拥有提高效率的潜能。如果这个视图的字节顺序和本地机器硬件的字节顺序一致,低等级的(相对于高级语言而言)语言的代码可以直接存取缓冲区中的数据值,而不是通过比特数据的包装和解包装过程来完成。
0 条评论
撰写评论