下面的示例简单演示了三种类型的流用以产生可写的、可读可写以及可读的通道。
public class GetChannel { private static final int BSIZE = 1024; public static void main(String[] args) throws IOException{ //通过通道和缓冲器写文件 FileChannel fChannel = new FileOutputStream("data.txt").getChannel(); fChannel.write(ByteBuffer.wrap("Some text ".getBytes())); fChannel.close(); //RandomAccessFile对文件的权限为可读可写 向文件data.txt末尾添加 fChannel = new RandomAccessFile("data.txt","rw").getChannel(); fChannel.position(fChannel.size()); fChannel.write(ByteBuffer.wrap("Some more".getBytes())); fChannel.close(); //通过通道和缓冲器读文件 fChannel = new RandomAccessFile("data.txt").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BSIZE); fChannel.read(buffer); buffer.flip();//让别人做好读取字节的准备 while(buffer.hasRemaining()) { System.out.print((char)buffer.get()); } } }FileOutputStream、RandomAccessFile和RandomAccessFile都有一个getChannel()方法产生一个FileChannel与实际文件关联。在以上程序中,我们使用ByteBuffer向FileChannel通道中传入数据和获取数据,就像前面提过的,通道从缓冲器获取数据或者向缓冲器发送数据。
将字节存放于ByteBuffer中的方法之一是:使用一种“put”方法直接对它们进行填充,填入一个或多个字节,或者基本数据类型的值。不过,正如程序中所见可以使用warp()方法将已存在的字节数组“包装”到ByteBuffer中。这样,就不会再复制底层的数组,而是把它作为所产生的ByteBuffer的存储器,我们称之为数组支持的ByteBuffer。
从通道中获取数据,我们使用ByteBuffer.allocate()分配了缓冲器的大小。若是我们想要达到更快的速度,也可以使用allocateDirect(),这个将产生一个与操作系统有更高耦合性的“直接”缓冲器。但是,这种分配的开始也会很大,而且也会随着操作系统的不同而不同,因此需要依照实际来选择。
看ByteBuffer作为桥梁在两个通道之间传递数据(文件复制)的例子:
public class ChannelCopy { private static final int BSIZE = 1024; public static void main(String[] args) throws IOException{ FileChannel in = new FileInputStream("in.txt").getChannel(); FileChannel out = new FileOutputStream("out.txt").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BSIZE); while((in.read(buffer)) != -1) { buffer.flip(); //通知别人准备读取 out.write(buffer); //通道从buffer中获取数据 buffer.clear(); //清除buffer准备下一次数据的读取 } } }打开两个FileChannel,一个用于读取一个用于写入。每次read()之后,数据就会被写入到缓冲器中,flip()则准备缓冲器以便它的信息可以由write()提取。write()操作之后,信息仍然存在缓冲器中,接着clear()操作则对所有的内部指针重新安排,以便缓冲器在另外一个read()操作前能够做好接受数据的准备。
然而,使用一个缓冲器当做桥梁完成这种操作不是最恰当的方法。特殊方法transferTo()和transferFrom()则允许我们将一个通道和另一个通道直接相连:
public class ChannelCopy2 { private static final int BSIZE = 1024; public static void main(String[] args) throws IOException{ FileChannel in = new FileInputStream("in.txt").getChannel(); FileChannel out = new FileOutputStream("out.txt").getChannel(); in.transferTo(0,in.size(),out); } } 将字节数据转换为字符串 public class BufferToText { private static final int BSIZE = 1024; public static void main(String[] args) throws IOException{ FileChannel fc = new FileOutputStream("data2.txt").getChannel(); fc.write(ByteBuffer.wrap("Some words ".getBytes())); fc.close(); fc = new FileInputStream("data2.txt").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BSIZE); fc.read(buffer); buffer.flip(); //直接输出asCharBuffer() System.out.println(buffer.asCharBuffer()); //----------------------- //回到缓冲器数据开始部分 buffer.rewind(); //发现默认字符集 String enconding = System.getProperty("file.encoding"); //取出缓冲器中的数据进行解码 System.out.println("Decoding using " + enconding + ": " +Charset.forName(enconding).decode(buffer)); fc = new FileOutputStream("data2.txt").getChannel(); //在输出数据时进行编码 fc.write(ByteBuffer.wrap("some beautiful flowers".getBytes("UTF-16BE"))); fc.close(); //获取编码后的数据 fc = new FileInputStream("data2.txt").getChannel(); buffer.clear(); fc.read(buffer); buffer.flip(); System.out.println(buffer.asCharBuffer()); //------------------------ fc = new FileOutputStream("data2.txt").getChannel(); buffer = ByteBuffer.allocate(12); //分配了24字节 //通过CharBuffer向ByteBuffer写入 buffer.asCharBuffer().put("Some"); fc.write(buffer); fc.close(); fc = new FileInputStream("data2.txt").getChannel(); buffer.clear(); fc.read(buffer); buffer.flip(); System.out.println(buffer.asCharBuffer()); } }