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

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

/** * 利用NIO进行文件复制 */
public class NIOFileCopy {
    public static void main(String[] args) {
        //建立文件读取通道

        //建立文件写入通道

        //读取到buffer

        //写入到目标通道
    }
}

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

//建立读取文件通道以及写入文件通道
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当中去:框架

//读取到buffer
ByteBuffer 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。这也是它比输入输出流的思想要先进,封装的想法也更加完善。以下:svg

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工具类建立channel
FileChannel channel = Files.newByteChannel(path, options); 
//经过Channels工具类,建立channel对象
Channels.newChannel(inputstream);

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

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

能够经过多种重载方式来完成这个文件复制操做,因此咱们其实能够用一行代码完成上面全部代码完成的事情,以下:xml

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

更多文件复制这一块的内容及细节你们能够经过阅读API来细细体会。