byteBuffer的用法

上传人:206****923 文档编号:41228964 上传时间:2018-05-28 格式:DOCX 页数:9 大小:16.90KB
返回 下载 相关 举报
byteBuffer的用法_第1页
第1页 / 共9页
byteBuffer的用法_第2页
第2页 / 共9页
byteBuffer的用法_第3页
第3页 / 共9页
byteBuffer的用法_第4页
第4页 / 共9页
byteBuffer的用法_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《byteBuffer的用法》由会员分享,可在线阅读,更多相关《byteBuffer的用法(9页珍藏版)》请在金锄头文库上搜索。

1、byteBuffer 的使用之道的使用之道分类: JAVA 2011-11-08 22:281918人阅读评论(0)收藏举报bytebufferimportiteratorexception 网络应用缓冲区分配和包装在能够读和写之前,必须有一个缓冲区,用静态方法 allocate() 来分配缓冲区:ByteBuffer buffer = ByteBuffer.allocate(1024);allocate() 方法分配一个具有指定大小的底层数组,并将它包装到一个缓冲区对象中 在本例中是一个 ByteBuffer。还可以将一个现有的数组转换为缓冲区:byte array = new byte10

2、24;ByteBuffer buffer = ByteBuffer.wrap(array);本例使用了 wrap() 方法将一个数组包装为缓冲区。一旦完成包装,底层数据就可以通过缓冲区或者直接访问。缓冲区分片slice() 方法根据现有的缓冲区创建一个 子缓冲区。也就是它创建一个新的缓冲区,新缓冲区与原来的缓冲区的一部分共享数据。首先创建一个长度为 10 的 ByteBuffer:ByteBuffer buffer = ByteBuffer.allocate(10);然后使用数据来填充这个缓冲区,在第 n 个槽中放入数字 n:for (int i = 0; i buffer.capacity(

3、); i+) buffer.put(byte)i);现在我们对这个缓冲区 分片,以创建一个包含槽 3 到槽 6 的子缓冲区。在某种意义上,子缓冲区就像原来的缓冲区中的一个 窗口 。窗口的起始和结束位置通过设置 position 和 limit 值来指定,然后调用 Buffer 的 slice() 方法:buffer.position(3);buffer.limit(7);ByteBuffer slice = buffer.slice();片 是缓冲区的 子缓冲区 。不过,片段 和 缓冲区 共享同一个底层数据数组。缓冲区份片和数据共享遍历子缓冲区,将每一个元素乘以 11 来改变它。例如,5 会变

4、成 55。for (int i = 0; i slice.capacity(); i+) byte b = slice.get(i);b *= 11;slice.put(i, b);原缓冲区中的内容:buffer.position( 0 );buffer.limit(buffer.capacity();while (buffer.hasRemaining() System.out.println(buffer.get();结果表明只有在子缓冲区窗口中的元素被改变了:java SliceBuffer01233445566789缓冲区片对于促进抽象非常有帮助。可以编写自己的函数处理整个缓冲区,而且

5、如果想要将这个过程应用于子缓冲区上,只需取主缓冲区的一个片,并将它传递给您的函数。这比编写自己的函数来取额外的参数以指定要对缓冲区的哪一部分进行操作更容易。只读缓冲区只读缓冲区非常简单 可以读取它们,但是不能向它们写入。可以通过调用缓冲区的 asReadOnlyBuffer() 方法,将任何常规缓冲区转换为只读缓冲区,这个方法返回一个与原缓冲区完全相同的缓冲区(并与其共享数据),只不过它是只读的。只读缓冲区对于保护数据很有用。在将缓冲区传递给某个对象的方法时,您无法知道这个方法是否会修改缓冲区中的数据。创建一个只读的缓冲区可以 保证 该缓冲区不会被修改。不能将只读的缓冲区转换为可写的缓冲区。内

6、存映射文件 I/O内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。内存映射文件 I/O 是通过使文件中的数据神奇般地出现为内存数组的内容来完成的。这其初听起来似乎不过就是将整个文件读到内存中,但是事实上并不是这样。一般来说,只有文件中实际读取或者写入的部分才会送入(或者 映射 )到内存中。内存映射并不真的神奇或者多么不寻常。现代操作系统一般根据需要将文件的部分映射为内存的部分,从而实现文件系统。Java 内存映射机制不过是在底层操作系统中可以采用这种机制时,提供了对该机制的访问。尽管创建内存映射文件相当简单,但是向它写入可能是危险的。仅只是

7、改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。将文件映射到内存了解内存映射的最好方法是使用例子。在下面的例子中,要将一个 FileChannel (它的全部或者部分)映射到内存中。为此将使用 FileChannel.map() 方法。下面代码行将文件的前 1024 个字节映射到内存中:MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024 );map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,可以像使用

8、其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行行映射。import java.io.RandomAccessFile;import java.nio.MappedByteBuffer;import java.nio.channels.FileChannel;public class UseMappedFile private static final int start = 0;private static final int size = 1024;public static void main(String args) throws Exception

9、RandomAccessFile raf = new RandomAccessFile(“C:usemappedfile.txt“, “rw“);FileChannel fc = raf.getChannel();MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, start, size);mbb.put(0, (byte)97);mbb.put(1023, (byte)122);raf.close();分散和聚集分散/聚集 I/O 是使用多个而不是单个缓冲区来保存数据的读写方法。一个分散的读取就像一个常规通道读取,只不过

10、它是将数据读到一个缓冲区数组中而不是读到单个缓冲区中。同样地,一个聚集写入是向缓冲区数组而不是向单个缓冲区写入数据。分散/聚集 I/O 对于将数据流划分为单独的部分很有用,这有助于实现复杂的数据格式。分散/聚集 I/O通道可以有选择地实现两个新的接口: ScatteringByteChannel 和 GatheringByteChannel。一个 ScatteringByteChannel 是一个具有两个附加读方法的通道:long read(ByteBuffer dsts);long read(ByteBuffer dsts, int offset, int length);这些 long r

11、ead() 方法很像标准的 read 方法,只不过它们不是取单个缓冲区而是取一个缓冲区数组。在 分散读取 中,通道依次填充每个缓冲区。填满一个缓冲区后,它就开始填充下一个。在某种意义上,缓冲区数组就像一个大缓冲区。分散/聚集 I/O 对于将数据划分为几个部分很有用。例如,您可能在编写一个使用消息对象的网络应用程序,每一个消息被划分为固定长度的头部和固定长度的正文。您可以创建一个刚好可以容纳头部的缓冲区和另一个刚好可以容难正文的缓冲区。当您将它们放入一个数组中并使用分散读取来向它们读入消息时,头部和正文将整齐地划分到这两个缓冲区中。从缓冲区所得到的方便性对于缓冲区数组同样有效。因为每一个缓冲区都

12、跟踪自己还可以接受多少数据,所以分散读取会自动找到有空间接受数据的第一个缓冲区。在这个缓冲区填满后,它就会移动到下一个缓冲区。聚集写入聚集写入 类似于分散读取,只不过是用来写入。它也有接受缓冲区数组的方法:long write(ByteBuffer srcs);long write(ByteBuffer srcs, int offset, int length);聚集写对于把一组单独的缓冲区中组成单个数据流很有用。为了与上面的消息例子保持一致,您可以使用聚集写入来自动将网络消息的各个部分组装为单个数据流,以便跨越网络传输消息。异步 I/O异步 I/O 是一种 没有阻塞地 读写数据的方法。通常,

13、在代码进行 read() 调用时,代码会阻塞直至有可供读取的数据。同样, write() 调用将会阻塞直至数据能够写入。另一方面,异步 I/O 调用不会阻塞。相反,您将注册对特定 I/O 事件的兴趣 可读的数据的到达、新的套接字连接,等等,而在发生这样的事件时,系统将会告诉您。异步 I/O 的一个优势在于,它允许您同时根据大量的输入和输出执行 I/O。同步程序常常要求助于轮询,或者创建许许多多的线程以处理大量的连接。使用异步 I/O,您可以监听任何数量的通道上的事件,不用轮询,也不用额外的线程。异步 I/O 中的核心对象名为 Selector。Selector 就是您注册对各种 I/O 事件的

14、兴趣的地方,而且当那些事件发生时,就是这个对象告诉您所发生的事件。创建一个 SelectorSelector selector = Selector.open();然后,将对不同的通道对象调用 register() 方法,以便注册我们对这些对象中发生的 I/O 事件的兴趣。register() 的第一个参数总是这个 Selector。打开一个 ServerSocketChannel为了接收连接,需要一个 ServerSocketChannel。事实上,要监听的每一个端口都需要有一个 ServerSocketChannel 。对于每一个端口,打开一个 ServerSocketChannel,如下

15、所示:ServerSocketChannel ssc = ServerSocketChannel.open();ssc.configureBlocking( false );ServerSocket ss = ssc.socket();InetSocketAddress address = new InetSocketAddress(portsi);ss.bind( address );第一行创建一个新的 ServerSocketChannel,最后三行将它绑定到给定的端口。第二行将 ServerSocketChannel 设置为 非阻塞的 。必须对每一个要使用的套接字通道调用这个方法,否则异

16、步 I/O 就不能工作。选择键下一步是将新打开的 ServerSocketChannels 注册到 Selector 上。为此使用 ServerSocketChannel.register() 方法,如下所示:SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);register() 的第一个参数总是这个 Selector。第二个参数是 OP_ACCEPT,这里它指定我们想要监听 accept 事件,也就是在新的连接建立时所发生的事件。这是适用于 ServerSocketChannel 的唯一事件类型。请注意对 register() 的调用的返回值。 SelectionKey 代表这个通道在此 Selector 上的这个注册。当某个 Selector 通知您某个传入事件时,它是通过提供对应于该事件的 SelectionKey 来进行的。SelectionKey 还可以用于取消通道的注册。内部循环现在已经注册了对一些 I/O

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号