NIO学习笔记(三)——NIO复制文件

来源:互联网 发布:sublime js代码美化 编辑:程序博客网 时间:2024/05/22 00:23

前面我们已经学习了NIO的两大核心组件,channel和buffer。现在我们继续利用NIO来完成文件的复制操作。复制文件的步骤上与之前读取文件的步骤其实没有太大的区别,只不过使用了一套新的API而已。如下:

/** * 利用NIO进行文件复制 */public class NIOFileCopy {    public static void main(String[] args) {        //创建文件读取通道        //创建文件写入通道        //读取到buffer        //写入到目标通道    }}

接下来我们就把这部分程序来完成。首先创建读取文件通道:

//创建读取文件通道以及写入文件通道try (FileChannel srcChannel = FileChannel.open(Paths.get("f:/test.txt"), StandardOpenOption.READ);    FileChannel targetChannel = FileChannel.open(Paths.get("f:/test1.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {    /* do... */}

这里大家一定要习惯这个思路,在NIO这一部分,很多的内容都是通过静态的方法来创建对象的。读取文件通道的option的枚举类型为READ,同时在这里声明目标文件通道,同样的利用Paths.get方法声明文件路径。目标文件通道的option的枚举类型我们需要注意一下,如果目标文件不存在的话,单单一个WRITE是没办法把文件创建出来的,所以我们需要在这里追加一个参数——CREATE。open的option是一个可变长的参数,也就是说后面我们可以追加很多个StandardOpenOption参数设置,这里我们就为它设置了两个参数:WRITE和CREATE。

现在两个通道我们都创建完毕了,接着我们把目标读取到buffer当中去:

//读取到bufferByteBuffer buffer = ByteBuffer.allocate(1024);int flag = srcChannel.read(buffer);while(-1 != flag) {    //切换写模式到读模式 -> limit = position -> position = 0    buffer.flip();     while(buffer.remaining()) {        /* do... */    }    buffer.clear();    flag = srcChannel.read(buffer);}

读取至buffer的框架我们已经完成了,那么while循环里就可以进行写入到目标通道的工作了。上一节我们学习到,读取是通过buffer.get方法逐字节按position取,或者是我们直接通过buffer.array方法也能把byte数组取出来。不难想到,与读取相对应的就有一个buffer.put方法来写入。但我们如果进行文件复制,其实并不需要这么复杂。因为srcChannel和targetChannel可以公用这个buffer,我从srcChannel读出buffer,同样这个buffer也可以被用于写入targetChannel。这也是它比输入输出流的思想要先进,封装的想法也更加完善。如下:

while(-1 != flag) {    buffer.flip();     //写入到目标通道    int result = targetChannel.write(buffer);    System.out.println(result);    buffer.clear();    flag = srcChannel.read(buffer);}

这样我们就成功实现了对一个文件的复制,完整代码如下:

import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;/** * 利用NIO完成文件复制。 * @author 青葉 * */public class NIOFileCopy {    public static void main(String[] args) {        //创建读取文件通道        //创建写入文件通道        try(FileChannel srcChannel = FileChannel.open(Paths.get("f:/test.txt"), StandardOpenOption.READ);) {            FileChannel targetChannel = FileChannel.open(                    Paths.get("f:/test1.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);            //读取到buffer            ByteBuffer buffer = ByteBuffer.allocate(1024);            int flag = srcChannel.read(buffer);            while(-1 != flag) {                buffer.flip(); //切换写模式到读模式 -> limit = position -> position = 0                //写入到目标通道                int result = targetChannel.write(buffer);                System.out.println(result);                buffer.clear();                flag = srcChannel.read(buffer);            }        } catch (IOException e) {            e.printStackTrace();        }    }}

其实JDK1.7之后,还有两种方式可以创建FileChannel,在这里也顺带提一下。其中第二种方法很好的诠释了传统IO到NIO的过渡,如下:

//通过Files工具类创建channelFileChannel channel = Files.newByteChannel(path, options); //通过Channels工具类,创建channel对象Channels.newChannel(inputstream);

说到这里,这个Files类,它不单单可以创建channel,还有更加好用的一些方法。比如说我们这节介绍的文件复制的动作,其实在Files中,有一个方法可以直接完成这个动作——copy方法。它提供了3种重载,参数种类如下:

(1)2个路径 + 1个配置参数
(2)1个路径 + 1个输出流
(3)1个输入流 + 1个路径

可以通过多种重载方式来完成这个文件复制操作,所以我们其实可以用一行代码完成上面所有代码完成的事情,如下:

Files.copy(Paths.get("f:/test.txt"), Paths.get("f:/test1.txt"), StandardCopyOption.REPLACE_EXISTING);

更多文件复制这一块的内容及细节大家可以通过阅读API来细细体会。

原创粉丝点击