Java NIO使用及原理分析(三)(转)
在上一篇文章中介绍了缓冲区内部对于状态变化的跟踪机制,而对于NIO中缓冲区来说,还有很多的内容值的学习,如缓冲区的分片与数据共享,只读缓冲区等。在本文中我们来看一下缓冲区一些更细节的内容。
缓冲区的分配
在前面的几个例子中,我们已经看过了,在创建一个缓冲区对象时,会调用静态方法allocate()来指定缓冲区的容量,其实调用 allocate()相当于创建了一个指定大小的数组,并把它包装为缓冲区对象。或者我们也可以直接将一个现有的数组,包装为缓冲区对象,如下示例代码所示:
- public class BufferWrap {
- public void myMethod()
- {
- // 分配指定大小的缓冲区
- ByteBuffer buffer1 = ByteBuffer.allocate(10);
- // 包装一个现有的数组
- byte array[] = new byte[10];
- ByteBuffer buffer2 = ByteBuffer.wrap( array );
- }
- }
缓冲区分片
在NIO中,除了可以分配或者包装一个缓冲区对象外,还可以根据现有的缓冲区对象来创建一个子缓冲区,即在现有缓冲区上切出一片来作为一个新的缓冲区,但现有的缓冲区与创建的子缓冲区在底层数组层面上是数据共享的,也就是说,子缓冲区相当于是现有缓冲区的一个视图窗口。调用slice()方法可以创建一个子缓冲区,让我们通过例子来看一下:
- import java.nio.*;
- public class Program {
- static public void main( String args[] ) throws Exception {
- ByteBuffer buffer = ByteBuffer.allocate( 10 );
- // 缓冲区中的数据0-9
- for (int i=0; i<buffer.capacity(); ++i) {
- buffer.put( (byte)i );
- }
- // 创建子缓冲区
- buffer.position( 3 );
- buffer.limit( 7 );
- ByteBuffer slice = buffer.slice();
- // 改变子缓冲区的内容
- for (int i=0; i<slice.capacity(); ++i) {
- byte b = slice.get( i );
- b *= 10;
- slice.put( i, b );
- }
- buffer.position( 0 );
- buffer.limit( buffer.capacity() );
- while (buffer.remaining()>0) {
- System.out.println( buffer.get() );
- }
- }
- }
在该示例中,分配了一个容量大小为10的缓冲区,并在其中放入了数据0-9,而在该缓冲区基础之上又创建了一个子缓冲区,并改变子缓冲区中的内容,从最后输出的结果来看,只有子缓冲区“可见的”那部分数据发生了变化,并且说明子缓冲区与原缓冲区是数据共享的,输出结果如下所示:

只读缓冲区
只读缓冲区非常简单,可以读取它们,但是不能向它们写入数据。可以通过调用缓冲区的asReadOnlyBuffer()方法,将任何常规缓冲区转 换为只读缓冲区,这个方法返回一个与原缓冲区完全相同的缓冲区,并与原缓冲区共享数据,只不过它是只读的。如果原缓冲区的内容发生了变化,只读缓冲区的内容也随之发生变化:
- import java.nio.*;
- public class Program {
- static public void main( String args[] ) throws Exception {
- ByteBuffer buffer = ByteBuffer.allocate( 10 );
- // 缓冲区中的数据0-9
- for (int i=0; i<buffer.capacity(); ++i) {
- buffer.put( (byte)i );
- }
- // 创建只读缓冲区
- ByteBuffer readonly = buffer.asReadOnlyBuffer();
- // 改变原缓冲区的内容
- for (int i=0; i<buffer.capacity(); ++i) {
- byte b = buffer.get( i );
- b *= 10;
- buffer.put( i, b );
- }
- readonly.position(0);
- readonly.limit(buffer.capacity());
- // 只读缓冲区的内容也随之改变
- while (readonly.remaining()>0) {
- System.out.println( readonly.get());
- }
- }
- }
如果尝试修改只读缓冲区的内容,则会报ReadOnlyBufferException异常。只读缓冲区对于保护数据很有用。在将缓冲区传递给某个 对象的方法时,无法知道这个方法是否会修改缓冲区中的数据。创建一个只读的缓冲区可以保证该缓冲区不会被修改。只可以把常规缓冲区转换为只读缓冲区,而不能将只读的缓冲区转换为可写的缓冲区。
直接缓冲区
直接缓冲区是为加快I/O速度,使用一种特殊方式为其分配内存的缓冲区,JDK文档中的描述为:给定一个直接字节缓冲区,Java虚拟机将尽最大努 力直接对它执行本机I/O操作。也就是说,它会在每一次调用底层操作系统的本机I/O操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中 或者从一个中间缓冲区中拷贝数据。要分配直接缓冲区,需要调用allocateDirect()方法,而不是allocate()方法,使用方式与普通缓冲区并无区别,如下面的拷贝文件示例:
- import java.io.*;
- import java.nio.*;
- import java.nio.channels.*;
- public class Program {
- static public void main( String args[] ) throws Exception {
- String infile = "c:\\test.txt";
- FileInputStream fin = new FileInputStream( infile );
- FileChannel fcin = fin.getChannel();
- String outfile = String.format("c:\\testcopy.txt");
- FileOutputStream fout = new FileOutputStream( outfile );
- FileChannel fcout = fout.getChannel();
- // 使用allocateDirect,而不是allocate
- ByteBuffer buffer = ByteBuffer.allocateDirect( 1024 );
- while (true) {
- buffer.clear();
- int r = fcin.read( buffer );
- if (r==-1) {
- break;
- }
- buffer.flip();
- fcout.write( buffer );
- }
- }
- }
内存映射文件I/O
内存映射文件I/O是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的I/O快的多。内存映射文件I/O是通过使文件中的数据出现为 内存数组的内容来完成的,这其初听起来似乎不过就是将整个文件读到内存中,但是事实上并不是这样。一般来说,只有文件中实际读取或者写入的部分才会映射到内存中。如下面的示例代码:
- import java.io.*;
- import java.nio.*;
- import java.nio.channels.*;
- public class Program {
- static private final int start = 0;<span style="font-family:FangSong_GB2312;font-size:13px;">
- static private final int size = 1024;
- static public void main( String args[] ) throws Exception {
- RandomAccessFile raf = new RandomAccessFile( "c:\\test.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();
- }
- }</span>
关于缓冲区的细节内容,我们已经用了两篇文章来介绍。在下一篇中将会介绍NIO中更有趣的部分Nonblocking I/O。
原文地址:http://blog.csdn.net/wuxianglong/article/details/6612263
Java NIO使用及原理分析(三)(转)的更多相关文章
- Java NIO使用及原理分析 (四)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- Java NIO使用及原理分析 (四)(转)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- Java NIO使用及原理分析(1-4)(转)
转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...
- Java NIO使用及原理分析(二)
在第一篇中,我们介绍了NIO中的两个核心对象:缓冲区和通道,在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如 ...
- Java NIO使用及原理分析(二)(转)
在第一篇中,我们介绍了NIO中的两个核心对象:缓冲区和通道,在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如 ...
- Java NIO使用及原理分析 (一)(转)
最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下 ...
- Java NIO使用及原理分析(三)
在上一篇文章中介绍了缓冲区内部对于状态变化的跟踪机制,而对于NIO中缓冲区来说,还有很多的内容值的学习,如缓冲区的分片与数据共享,只读缓冲区等.在本文中我们来看一下缓冲区一些更细节的内容. 缓冲区的分 ...
- Java NIO使用及原理分析 (一)
http://blog.csdn.net/wuxianglong/article/details/6604817
- JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...
随机推荐
- IDEA创建maven项目jar更新缓慢问题
转自:http://www.cnblogs.com/ae6623/p/4416256.html 国内连接maven官方的仓库更新依赖库,网速一般很慢,收集一些国内快速的maven仓库镜像以备用. 最新 ...
- [译]流言终结者 —— SQL Server 是Sybase的产品而不是微软的
http://www.cnblogs.com/xxxtech/archive/2011/12/30/2307859.html by Euan Garden 这些年来我听说过关于这个流言的许多版本,其中 ...
- Android JUnit 入门指南
自动化单元测试可以做许多的事,并帮你节省时间.它也可以被用作快速检验新建工程或进行冒烟测试.始终,单元测试是作为一种有效的.系统的检验应用程序各功能执行的方式.Android SDK支持JUnit的自 ...
- 转inux Shell编程入门
http://www.cnblogs.com/suyang/archive/2008/05/18/1201990.html 从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来 ...
- Bridge - 桥接模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- Action中如何通过@Autowired自动注入spring bean ?
1.讲Action纳入spring的IOC控制 <!-- 采用注解方式自动扫描装配 --> <context:component-scan base-package="co ...
- struts2 循环标签使用
struts2 counter循环标签的使用: struts2随提供了循环控制标签<s:iterator/>,,使用起来也比较方便,但在具体的应用中,也有不方便之处,他没有像struts1 ...
- Spark核心概念理解
本文主要内容来自于<Hadoop权威指南>英文版中的Spark章节,能够说是个人的翻译版本号,涵盖了基本的Spark概念.假设想获得更好地阅读体验,能够訪问这里. 安装Spark 首先从s ...
- 网络编程之TCP/UDP及其流程比较(转)
TCP与UDP的区别 基于连接与无连接 对系统资源的要求(TCP较多,UDP少) UDP程序结构较简单 流模式与数据报模式TCP保证数据正确性,UDP可能丢包TCP保证数据顺序,UDP不保证 具体编程 ...
- 【Android】3.24 示例24--OpenGL绘制功能
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 百度地图SDK为广大开发者开放了OpenGL绘制接口,帮助开发者在地图上实现更灵活的样式绘制,丰富地 ...