学科分类
目录
Java基础

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个参数表示目标通道,即要传输到的位置。最后文件拷贝完毕后,关闭了所有的资源。

点击此处
隐藏目录