Channels和Buffers是JAVA NIO里面比较重要的两个概念,NIO正是基于Channels和Buffers进行数据操作,且数据总是从Channels读取到Buffers,或者从Buffers写入到Channels。
通道(Channel)
- 可以从通道写输入,也可以读数据;
- 通道的数据是跟Buffer进行交互的,数据可以读到Buffer,也可以从Buffer写数据到通道;
- 还可以异步读写数据;
以FileChannel为例,如下:
FileChannel
FileChannel是文件写入/读取相关的通道;
产生FileChannel的方式:
- 从FileOutputStream中获取;
- 从RandomAccessFile中获取;
- 从FileInputStream中获取;
下面举个例子,分别从FileOutputStream、RandomAccessFile、FileInputStream中获取文件通道,进行相关写入/读取操作;
package com.pichen.io;import java.nio.*;import java.nio.channels.*;import java.io.*;public class GetChannel { private static final int BSIZE = 1024; public static void main(String[] args) throws Exception { // 创建文件输出字节流 FileOutputStream fos = new FileOutputStream("data.txt"); //得到文件通道 FileChannel fc = fos.getChannel(); //往通道写入ByteBuffer fc.write(ByteBuffer.wrap("Some text ".getBytes())); //关闭流 fos.close(); //随机访问文件 RandomAccessFile raf = new RandomAccessFile("data.txt", "rw"); //得到文件通道 fc = raf.getChannel(); //设置通道的文件位置 为末尾 fc.position(fc.size()); //往通道写入ByteBuffer fc.write(ByteBuffer.wrap("Some more".getBytes())); //关闭 raf.close(); //创建文件输入流 FileInputStream fs = new FileInputStream("data.txt"); //得到文件通道 fc = fs.getChannel(); //分配ByteBuffer空间大小 ByteBuffer buff = ByteBuffer.allocate(BSIZE); //从通道中读取ByteBuffer fc.read(buff); //调用此方法为一系列通道写入或相对获取 操作做好准备 buff.flip(); //从ByteBuffer从依次读取字节并打印 while (buff.hasRemaining()){ System.out.print((char) buff.get()); } fs.close(); }}
再举个文件复制的例子,有两种方式:
- 打开一个FileChannel用于读,另一个用于写;
- 直接调用transferTo或者transferFrom方法传输通道之间的数据;
如下代码示例:
package com.pichen.io;import java.nio.*;import java.nio.channels.*;import java.io.*;public class ChannelCopy { private static final int BSIZE = 1024; public static void main(String[] args) throws Exception { //获取文件输入输出字节流 FileInputStream fis = new FileInputStream("C:\\test.jpg"); FileOutputStream fos = new FileOutputStream("C:\\test_copy.jpg"); //从文件输入输出字节流中获取通道 FileChannel fci = fis.getChannel(); FileChannel fco = fos.getChannel(); //分配ByteBuffer空间大小 ByteBuffer buffer = ByteBuffer.allocate(BSIZE); //第一种种数据拷贝方式,直接往输入通道写数据 while (fci.read(buffer) != -1) { //为写入操作做准备 buffer.flip(); //往输出通道写入buffer fco.write(buffer); //清空buffer,重置内部指针 buffer.clear(); } //第二种数据拷贝方式,利用transferTo或者transferFrom方式 FileOutputStream fos2 = new FileOutputStream("C:\\test_copy2.jpg"); FileChannel fco2 = fos.getChannel(); fci.transferTo(0, fci.size(), fco2); fis.close(); fos.close(); fos2.close(); }}
缓冲区(Buffer)
buffer用于与通道进行交互,举个例子如下,这里以ByteBuffer为例;
package com.pichen.io;import java.nio.*;import java.nio.channels.*;import java.io.*;public class GetChannel { private static final int BSIZE = 1024; public static void main(String[] args) throws Exception { // 随机访问文件 RandomAccessFile raf = new RandomAccessFile("C:\\data.txt", "rw"); // 得到文件通道 FileChannel fc = raf.getChannel(); ByteBuffer bf = ByteBuffer.allocate(BSIZE); int bytesRead = fc.read(bf); // read into buffer. while (bytesRead != -1) { // 通过flip()方法将Buffer从写模式切换到读模式 bf.flip(); while (bf.hasRemaining()) { // 每次读取一个字节 System.out.print((char) bf.get()); } // 清空缓存,准备往缓存写数据 bf.clear(); bytesRead = fc.read(bf); } // 关闭 raf.close(); }}
Buffer基本方法
- flip方法:从buffer读数据之前调用,从写模式切换到读模式;
- clear:往buffer写数据之前调用,全部清除;
compact
:往buffer写数据之前调用,只清除已读取的数据,新写入的数据会添加到未读数据末尾;
Buffer基本属性
- capacity:buffer空间大小;
- position:读写数据时的指针,指向当前位置;
- limit:读数据时,表示当前可读数据的大小;写数据时,即buffer大小=capacity;
Buffer的类型
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Buffer中写数据
- 从Channel写到Buffer,调用通道的read
(
Buffer
buffer)方法 - put()方法写到Buffer里
,调用
Buffer的put方法
Buffer中读取数据
- 从Buffer读取数据到Channel,调用通道的
write
(
Buffer
buffer)方法 - 使用get()方法从Buffer中读取数据,
调用
Buffer的get方法
参考:http://ifeve.com/java-nio-all/