● 获取缓冲区对象
一共有两种类型的缓冲区,直接缓冲区和非直接缓冲区,两者区别在于直接缓冲区上的数据操作,
虚拟机将尽量使用本机I/O,并尽量避免使用中间缓冲区。判断一个缓冲区是否是直接缓冲区,
可以调用isDirect()方法。
有三种方式来获取一个缓冲区的对象:
a. 调用allocate()或者allocateDirect()方法直接分配,其中allocateDirect()
返回的是直接缓冲区。
b. 包装一个数组,如:
byte[] b = new byte[1024];
ByteBuffer bb = ByteBuffer.wrap(b);
c. 内存映射,即调用FileChannel的map()方法。
● 缓冲区基本属性
这几个属性是每个缓冲区都有的并且是常用的操作。
a. 容量(capacity),缓冲区大小
b. 限制(limit),第一个不应被读取或写入的字节的索引,总是小于容量。
c. 位置(position),下一个被读取或写入的字节的索引,总是小于限制。
d. clear()方法:设置limit为capacity,position为0。
e. filp()方法:设置limit为当前position,然后设置position为0。
f. rewind()方法:保持limit不变,设置position为0。
● 缓冲区数据操作
操作包括了读取和写入数据两种。
读取数据使用get()及其系列方法,除boolean外,每一种类型包括了对应的get()方法,
如getInt(),getChar()等,get()方法用来读取字节,支持相对和绝对索引两种方式。
写入数据使用put()及其系列方法,和get()方法是对应的。
下面这个例子演示了如何使用缓冲区和信道:
package nio;import java.io.FileInputStream;import
java.io.FileOutputStream;import java.nio.ByteBuffer;import
java.nio.channels.FileChannel;public class BufferDemo ...
{ public static void main(String[] args) throws Exception...
{ //分配一个非直接缓冲区 ByteBuffer bb =
ByteBuffer.allocate(100); //向缓冲区写入0到100的字节制 for(int i =
0; i <100; i++)...{ byte b = (byte) (Math.random() *
100); bb.put(b); }
System.out.println("写入文件前的缓冲区数据"); bb.flip();
while(bb.hasRemaining()) System.out.print(bb.get() + "
"); System.out.println(); //获取一个关联到文件buffer.txt的信
道 FileChannel fc = new
FileOutputStream("buffer.txt").getChannel(); //将缓冲区数据写到文件
中 bb.flip(); fc.write(bb); //防止缓存
fc.force(true); //关闭信道 fc.close(); bb =
null; fc = null; //下面从文件中读取数据 fc = new
FileInputStream("buffer.txt").getChannel(); ByteBuffer bb2 =
ByteBuffer.allocate((int) fc.size()); fc.read(bb2);
System.out.println("从文件读取的缓冲区数据"); bb2.flip();
while(bb2.hasRemaining()) System.out.print(bb2.get() + "
"); System.out.println(); fc.close(); bb2 =
null; fc = null; }}
3.视图缓冲区
上面我们的缓冲区都是基于字节的,像IntBuffer、LongBuffer等这些都可以调用ByteBuffer的
as***Buffer(***表示某个数据类型)得到,所以这种类型的缓冲区又被称为视图缓冲区(View Buffer),
视图缓冲区有以下特点:
a. 视图缓冲区有自己独立的position和limit,但它不是一个新的创建,只是原来字节缓冲区的一个逻辑缓冲区,字节缓冲区的任何修
改都会影响视图缓冲区,反之亦然。
b. 视图缓冲区按照数据类型的大小进行索引,而不是字节顺序。
c. 也提供了put()和get()及其系列方法,用于数据的整块传输。
下面这个例子演示了视图缓冲区:
package nio;import java.io.FileInputStream;import
java.nio.ByteBuffer;import java.nio.IntBuffer;import
java.nio.channels.FileChannel;public class ViewBufferDemo ...
{ public static void main(String[] args) throws Exception...
{ //将文件内容读到缓冲区中 FileChannel fc = new
FileInputStream("buffer.txt").getChannel(); ByteBuffer bb =
ByteBuffer.allocate((int) fc.size()); fc.read(bb);
fc.close(); fc = null; System.out.println("从文件读取的
字节缓冲区数据"); bb.flip();
while(bb.hasRemaining()) System.out.print(bb.get() + "
"); System.out.println(); //获取视图缓冲区
bb.flip(); IntBuffer ib = bb.asIntBuffer();
System.out.println("将字节缓冲区作为整形缓冲区的数据");
while(ib.hasRemaining()) System.out.print(ib.get() + "
"); System.out.println(); bb = null; ib =
null; }}
4.映射内存缓冲区
调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是一
个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:
a. 内存映射I/O是对信道/缓冲区技术的改进。 当传输大量的数据时,内存映射I/O
速度相对较快,这是因为它使用虚拟内存把文件传输到进程的地址空间中。
b. 映射内存也成为共享内存,因此可以用于相关进程(均映射同一文件)之间的整块数据
传输,这些进程甚至可以不必位于同一系统上,只要每个都可以访问同一文件即可。
c. 当对FileChannel执行映射操作,把文件映射到内存中时,得到的是一个连接到文件的
映射的字节缓冲区,这种映射的结果是,当输出缓冲区的内容时,数据将出现在文件中,
当读入缓冲区时,相当于得到文件中的数据。
下面这个例子演示了映射内存:
package nio;import java.io.FileInputStream;import
java.io.FileOutputStream;import java.nio.MappedByteBuffer;import
java.nio.channels.FileChannel;public class CopyFile ...{ public
static void main(String[] args) throws Exception ...
{ FileChannel fIChan, fOChan; MappedByteBuffer
mBuf; fIChan = new
FileInputStream("buffer.txt").getChannel(); fOChan = new
FileOutputStream("bufferTemp.txt").getChannel(); mBuf =
fIChan.map(FileChannel.MapMode.READ_ONLY, 0, fIChan.size());
fOChan.write(mBuf); fIChan.close();
fOChan.close(); fIChan = null; fOChan =
null; mBuf = null; }}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1133382