在操作系统里面有一copy命令,这个命令的主要功能是可以实现文件的拷贝处理,现在要求模拟这个命令输入拷贝的源文件路径与要拷贝的目标路径实现拷贝处理。

需要分析:

  • 需要实现文件的拷贝操作,那么这种拷贝就有可能拷贝各种类型的文件,所以肯定使用字节流;
  • 在进行拷贝的时候有可能需要考虑大文件的拷贝问题;

实现方案:

  • 方案一:使用InputStream将全部要拷贝的内容直接读取到程序里面,而后一次性的输出到目标文件。

如果拷贝的文件很大,基本上程序就死了。

  • 方案二:采用部分拷贝,读取一部分,输出一部分,如果现在要采用第二种做法,核心的方法:

IntputStream:public int read(byte[] b, int off, int len) throws IOException;读取一部分内容

OutputStream:public void write(byte[] b, int off, int len) throws IOException;写入一部分内容

范例:实现文件拷贝处理

package 字节流与字符流;

import java.io.*;

public class 文件拷贝处理 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();    //开始计时
        FileUtil fileUtil = new FileUtil("F:"+File.separator+"Test"+File.separator+"test.txt","F:"+File.separator+"Test"+File.separator+"write.txt");
        try {
            System.out.println(fileUtil.copy() ? "文件拷贝成功" : "文件拷贝失败");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end  = System.currentTimeMillis();     //结束计时
        System.out.println("拷贝完成时间"+(end - start));
    }
}
//定义一个操作的工具类
class FileUtil{
    private File srcFile;   //源文件路径
    private File desFile;   //目标文件路径

    FileUtil(File srcFile,File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }

    /**
     * 将传入的路径实例化并调用构造方法执行
     * @param srcFile   String类型的路径文件
     * @param desFile   String类型的路径文件
     */
    FileUtil(String srcFile,String desFile){
        this(new File(srcFile), new File(desFile));
    }

    /**
     * 文件拷贝处理
     * @return  拷贝成功为true,否则为false
     * @throws IOException
     */
    public boolean copy() throws Exception {
        if(!this.srcFile.exists()){  //源文件不存在
            System.out.println("要拷贝的源文件不存在");
            return false;
        }
        if(!this.desFile.getParentFile().exists()){ //
            this.desFile.getParentFile().mkdirs();  //创建父目录
        }


        byte[] data = new byte[1024];   //开辟一个拷贝的缓冲区
        InputStream input = null;
        OutputStream output = null;

        try {
            //实例化InputStream与OutputStream对象
            input = new FileInputStream(this.srcFile);
            output = new FileOutputStream(this.desFile);
            int len;

            //读取一些字节数到数组之中,随后返回读取的个数
            //判断个数是否是-1,如果不是则写入
           while ((len = input.read(data)) != -1){
               output.write(data,0,len);
           }

            return true;
        }catch (Exception e){
            throw e;
        } finally {
            if(input != null){
                input.close();
            }
            if(output != null){
                input.close();
            }
        }
    }
}

文件拷贝成功
拷贝完成时间41

但是需要注意的是,以上的做法是属于稳健拷贝的最原始实现,而从JDK1.9开始IputStream和Reader类中都追加有数据转存的处理方法:

  • InputStream:public long transferTo(OutputStream out) throws IOexception;(从该输入流中读取所有字节,并按读取顺序将字节写入给定的输出流:)
  • Reader:public long transferTo(Writer out) throws IOException;(读取此阅读器中的所有字符,并按照读取的顺序将字符写入给定的编写器)

范例:使用转存的方式实现copy功能

package 字节流与字符流;

import java.io.*;

public class 文件拷贝处理 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();    //开始计时
        FileUtil fileUtil = new FileUtil("F:"+File.separator+"Test"+File.separator+"test.txt","F:"+File.separator+"Test"+File.separator+"write.txt");
        try {
            System.out.println(fileUtil.copy() ? "文件拷贝成功" : "文件拷贝失败");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end  = System.currentTimeMillis();     //结束计时
        System.out.println("拷贝完成时间"+(end - start));
    }
}
//定义一个操作的工具类
class FileUtil{
    private File srcFile;   //源文件路径
    private File desFile;   //目标文件路径

    FileUtil(File srcFile,File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }

    /**
     * 将传入的路径实例化并调用构造方法执行
     * @param srcFile   String类型的路径文件
     * @param desFile   String类型的路径文件
     */
    FileUtil(String srcFile,String desFile){
        this(new File(srcFile), new File(desFile));
    }

    /**
     * 文件拷贝处理
     * @return  拷贝成功为true,否则为false
     * @throws IOException
     */
    public boolean copy() throws Exception {
        if(!this.srcFile.exists()){  //源文件不存在
            System.out.println("要拷贝的源文件不存在");
            return false;
        }
        if(!this.desFile.getParentFile().exists()){ //
            this.desFile.getParentFile().mkdirs();  //创建父目录
        }


        byte[] data = new byte[1024];   //开辟一个拷贝的缓冲区
        InputStream input = null;
        OutputStream output = null;

        try {
            //实例化InputStream与OutputStream对象
            input = new FileInputStream(this.srcFile);
            output = new FileOutputStream(this.desFile);
            input.transferTo(output);   //将input中的所有字节数据读取并按顺序并写入到output
            return true;
        }catch (Exception e){
            throw e;
        } finally {
            if(input != null){
                input.close();
            }
            if(output != null){
                input.close();
            }
        }
    }
}

文件拷贝成功
拷贝完成时间16

此时需要注意版本问题,如果对此数据要求进一步扩产,可以实现一个文件目录的拷贝?一旦进行目录的拷贝还需要拷贝所有子目录的文件。 

package 字节流与字符流;

import java.io.*;

public class 文件拷贝处理 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();    //开始计时
        String addressA = "F:"+File.separator+"360极速浏览器";
        String addressB = "F:"+File.separator+"Test2";
        FileUtil fileUtil = new FileUtil(addressA,addressB);
        try {
            if(new File(addressA).isFile()){    //文件拷贝
                System.out.println(fileUtil.copy() ? "文件拷贝成功" : "文件拷贝失败");
            }else{  //目录拷贝
                System.out.println(fileUtil.copyDir() ? "目录拷贝成功" : "目录拷贝失败");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        long end  = System.currentTimeMillis();     //结束计时
        System.out.println("拷贝完成时间"+(end - start));
    }
}
//定义一个操作的工具类
class FileUtil {
    private File srcFile;   //源文件路径
    private File desFile;   //目标文件路径

    FileUtil(File srcFile, File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }

    /**
     * 文件拷贝私有方法
     * @param srcFile   被拷贝的文件路径
     * @param desFile   要拷贝过去的文件路径
     * @return  成功表示true,反之false
     * @throws Exception    IOException
     */
    private boolean copyFileImpl(File srcFile,File desFile) throws Exception {
        if (!desFile.getParentFile().exists()) { //父目录不存在
            desFile.getParentFile().mkdirs();  //创建父目录
        }

        byte[] data = new byte[1024];   //开辟一个拷贝的缓冲区
        InputStream input = null;
        OutputStream output = null;

        try {
            //实例化InputStream与OutputStream对象
            input = new FileInputStream(srcFile);
            output = new FileOutputStream(desFile);
            input.transferTo(output);   //将input中的所有字节数据读取并按顺序并写入到output
            return true;
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
            if (output != null) {
                input.close();
            }
        }
    }

    private void copyImpl(File file) throws Exception {
        if (file.isDirectory()) { //是目录
            File[] results = file.listFiles();   //列出全部目录组成
            if (results != null) {    //系统设置权限的文件不能被操作
                for (int x = 0; x < results.length; x++) {
                    copyImpl(results[x]);    //递归调用
                }
            }
        } else { //是文件
            String newFilePath = file.getPath().replace(this.srcFile.getPath() + File.separator, "");
            File newFile = new File(this.desFile, newFilePath);   //拷贝的路径
            this.copyFileImpl(file, newFile);    //调用拷贝方法来完成
        }
    }


    /**
     * 将传入的路径实例化并调用构造方法执行
     * @param srcFile String类型的路径文件
     * @param desFile String类型的路径文件
     */
    FileUtil(String srcFile, String desFile) {
        this(new File(srcFile), new File(desFile));
    }

    /**
     * 调用copyImpl()方法实现文件拷贝处理
     * @return 拷贝成功为true, 否则为false
     * @throws IOException
     */
    public boolean copy() throws Exception {
        if (!this.srcFile.exists()) {  //源文件不存在
            System.out.println("要拷贝的源文件不存在");
            return false;
        }
        return this.copyFileImpl(this.srcFile,this.desFile);
    }

    public boolean copyDir() throws Exception {
        try{
            this.copyImpl(this.srcFile);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }


}