Channel(通道)
Channel是一个接口对象,它类似于传统的流对象,但与传统的流对象又有些不同,具体表现如下:
● Channel可以异步的执行I/O读写操作。
● Channel的读写操作是双向的,既可以从Channel中读取数据,又可以写数据到Channel,而流的读写操作通常都是单向的。
● Channel可以直接将指定文件的部分或者全部直接映射成Buffer。
● Channel只能与Buffer进行交互,程序不能直接读写Channel中的数据。
要使用Channel,就需要使用它的实现类。在java.nio.channels包中,提供了很多Channel接口的实现类,包括DatagramChannel、FileChannel、Pipe.SinkChannel、Pipe.SourceChannel、ServerSocketChannel、SocketChannel等。其中DatagramChannel用于支持UDP网络通信,FileChannel用于从文件中读写数据,Pipe.SinkChannel和Pipe.SourceChannel用于支持线程之间的通信,ServerSocketChannel和SocketChannel用于支持TCP网络通信。这里将主要讲解FileChannel的使用。
Channel对象并不是通过构造方法来创建的,而是通过传统I/O的getChannel()方法来获取对应的Channel。不同的流所获取的Channel是不同的,例如FileInputStream和FileOutputStream获取的是FileChannel,同时还可以使用RandomAccessFile获取该对象,而PipedInputStream和PipedOutputStream所获得的是Pipe.SinkChannel和Pipe.SourceChannel。
FileChannel类可以实现常用的读写操作,在类中提供了很多专门用于操作文件的方法,其常用方法如表1所示。
表1 FileChannel类的常用方法
方法声明 | 功能描述 |
---|---|
MappedByteBuffer map(MapMode mode, long position, long size) | 将该通道文件的区域直接映射到内存中。其中第1个参数用于执行映射时的模式,包含只读、读写等模式;第2个参数表示映射区域开始的文件中的位置;第3个参数表示要映射区域的大小 |
long position() | 返回该通道的文件位置 |
Int read(ByteBuffer dst) | 从这个通道读取一个字节序列到给定的缓冲区 |
Int read(ByteBuffer dst, long position) | 从给定的文件位置开始,从这个通道读取一个字节序列到给定的缓冲区 |
long read(ByteBuffer[] dsts, int offset, int length) | 从这个通道读取一个字节序列到给定缓冲区的子序列 |
long size() | 返回该通道文件的当前大小 |
long transferTo(long position, long count, WritableByteChannel target) | 读取该通道文件中给定位置的字节数,并将它们写入目标通道 |
Int write(ByteBuffer src) | 从给定的缓冲区写入这个通道的字节序列 |
long write(ByteBuffer[] srcs, int offset, int length) | 从给定缓冲区的子序列中写入该通道的字节序列 |
Int write(ByteBuffer src, long position) | 从给定的缓冲区开始,从给定的文件位置开始向该通道写入一个字节序列 |
了解了FileChannel类的常用方法及其功能后,下面通过一个文件拷贝的案例,来演示FileChannel的使用,如文件1所示。
文件1 Example19.java
1 import java.io.*;
2 import java.nio.channels.*;
3 public class Example19 {
4 public static void main(String[] args) throws Exception {
5 // 创建RandomAccessFile对象,指定源文件
6 RandomAccessFile infile =
7 new RandomAccessFile("source/src.jpg","rw");
8 // 获取读取源文件FileChannel通道
9 FileChannel inChannel = infile.getChannel();
10 // 创建RandomAccessFile对象,指定目标文件
11 RandomAccessFile outfile =
12 new RandomAccessFile("target/dest.jpg","rw");
13 // 获取复制目标文件FileChannel通道
14 FileChannel outChannel = outfile.getChannel();
15 // 使用transferTo()方法进行整体复制
16 long transferTo = inChannel.transferTo(0, inChannel.size(),
17 outChannel);
18 if(transferTo>0){
19 System.out.println("复制成功!");
20 }
21 // 关闭资源
22 infile.close();
23 inChannel.close();
24 outfile.close();
25 outChannel.close();
26 }
27 }
运行结果如图1所示。
图1 运行结果
文件1中,使用RandomAccessFile类的构造方法生成两个RandomAccessFile对象,同时还指定了复制文件的源文件和目标文件名称以及可执行的操作,然后通过getChannel()方法获取对应的FileChannel类分别用于文件读取和写入通道。接下来通过FileChannel类的transferTo(long position, long count, WritableByteChannel target)方法实现了整个文件的拷贝,该方法的第1个参数表示所需转移文件的起始位置,这里表示从0开始;第2个参数表示要传输的最大字节数,这里通过size()方法获取了文件的字节数;第3个参数表示目标通道,即要传输到的位置。最后文件拷贝完毕后,关闭了所有的资源。