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 ... 
随机推荐
- java导出文件IE/Google文件名乱码兼容
			导出文件名乱码解决方案: String agent = request.getHeader("User-Agent"); boolean isMSIE = (agent != ... 
- 深入浅出Android开发之Surface介绍
			一 目的 本节的目的就是为了讲清楚Android中的Surface系统,大家耳熟能详的SurfaceFlinger到底是个什么东西,它的工作流程又是怎样的.当然,鉴于SurfaceFlinger的复杂 ... 
- 修改jQuery.validate验证方法和提示信息
			1.添加验证方法 在jquery.validate.js文件中直接添加验证方法,例如: jQuery.validator.addMethod("Specialstring", fu ... 
- Python istitle() 方法
			描述 istitle() 方法检测字符串中所有的单词拼写首字母是否为大写,且其他字母为小写. 语法 istitle() 方法语法: S.istitle() 参数 无. 返回值 如果字符串中所有的单词拼 ... 
- 使用xshell远程登录ubuntu使用vi编辑不能使用删除键方向键
			近期安装了xshell,远程登录上ubuntu后,在插入模式下,按删除键没有任何反应,按方向键分别打印出A.B.C.D,每个字符一行. 这是因为ubuntu初始化安装的是vi的tiny版本,解决办法安 ... 
- ubuntu中将某一程序设置为开机启动项的方法
			一.简要说明 Linux操作系统的引导加载程序(对个人电脑而言通常是LILO)开始,介绍Linux开机引导的步骤. 加载内核LILO启动之后,如果你选择了Linux作为准备引导的操作系统,第一个被加载 ... 
- xpages的combobox提前输入值
			之前的文档已经提到怎么在combobx手动输入.哪我们如何能够在combobox默认获取值呢?下面有几个种方法请大家參考 1)获取当前数据库某视图的某列值 @DbColumn(&quo ... 
- [swift]初始化方法自己主动继承
			子类默认不会继承父类的初始化方法,然而,假设某种条件满足的话.父类的初始化方法还是能够继承给子类.在通常情况下,这意味着你不必复写父类的初始化方法.在安全的前提下能够以最低的代价继承父类的初始化方法. ... 
- [Jobdu] 题目1545:奇怪的连通图
			题目描述: 已知一个无向带权图,求最小整数k.使仅使用权值小于等于k的边,节点1可以与节点n连通. 输入: 输入包含多组测试用例,每组测试用例的开头为一个整数n(1 <= n <= 100 ... 
- Bash Shell中Shift用法分享
			这篇文章主要介绍了Bash Shell中Shift的使用方法,需要的朋友可以参考下 shift可以用来向左移动位置参数.Shell的名字 $0第一个参数 $1第二个参数 $2第n个参数 $n所有参数 ... 
