java_多线程复制目录(探索)

这个代码在统计方面是有缺陷的.(线程嵌套)的不良一面

package experiment10.exp1;
/*用多线程的方法实现目录拷贝*/

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Scanner;

public class ThreadsCopy {
    static int count = 0;
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        //todo read
        System.out.println("输入被复制源目录名:");
        String sourceDirectory = scanner.nextLine();

        System.out.println("输入副本目标目录名");
        String destinationDirectory = scanner.nextLine();

        /*调用多线程复制函数*/
        long startTime = System.currentTimeMillis();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    copyDir(sourceDirectory, destinationDirectory);
                   // System.out.println(count+"---");
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //System.out.println(count+"!!!");
            }
        });

        thread.start();
        thread.join();
        //System.out.println("共启用了"+count+"个线程");
        //todo 这种做法主线程和次线程之间的相对执行顺序还是不明确的(比如主线程对静态变量的打印时机还是不受控的,尽管监视到的累加的最终值是不受影响的.
        // 很可能是我对线程嵌套的完整执行的理解不够深刻.;对join的理解不够深刻.
        // 目前我认为,线程嵌套的话,新开辟一个线程的语句执行完后,如果没有对应的join来阻塞(直到该线程完整执行完毕才执行下一行代码),那么如果我们想要让嵌套开辟的子线程完全回归,值得每一层配都有join了,如果不都配join,在统计开辟的线程数和运行时间上就比较头疼.
       //todo  相应而生的策略:先创建所有需要创建的进程,然后统一start;就解决了线程数的统计问题(统一join,就解决了时间统计的问题)(而且不会退化为单线程排队执行.
/*
Thread threadNew = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("共启用了"+count+"个线程");
    }
});
threadNew.start();
threadNew.join();*/
        System.out.println("共启用了"+count+"个线程");
        System.out.println("目录拷贝完成,共耗时" + (System.currentTimeMillis() - startTime) + "毫秒");
        // System.out.println("over!");
    }


    //todo 多线程嵌套递归的方式复制
    /*本递归复制函数具有检查并创建新目录的能力,*/
    static void copyDir(String oldPath, String newPath) throws IOException {
        System.out.println(count++);//testing(通过中途的内部打印来监视count的累计情况.)

        File file = new File(oldPath);
        String[] filePath = file.list();/*//当前路径下存在的目录名和文件名的数组.比较建议用list方法,不推荐用listFile方法,因为后面
        要通过连接目录名来创建新目录,用字符串比较方便.*/
        /*检查新目录是否存在.若不存在,则创建一个*/
        if (!(new File(newPath)).exists()) {
            (new File(newPath)).mkdir();//创建目录
        }
        /*遍历当前目录下的子目录和文件*/
//        for (int i = 0; i < filePath.length; i++)
        for (String x : filePath) {
            /*如果这(x)是一个子目录:(执行递归)*/
            if ((new File(oldPath + File.separator + x)).isDirectory()) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            copyDir(oldPath + File.separator + x, newPath + File.separator + x);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                thread.start();

            }

            /*如果x所指的是个文件:执行复制即可*/
            if (new File(oldPath + File.separator + x).isFile()) {
                File source = new File(oldPath + File.separator + x);
                File dest = new File(newPath + File.separator + x);
                if (!(dest.exists())) {
                    Files.copy(source.toPath(), dest.toPath());//创建新文件的能力
                }

            }
        }//endFor
        //System.out.println("The replication operation has been successfully executed!");
    }//endCopyFunction
}

继续修改

package experiment10.exp1;

import experiment9.FileName;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author xuchaoxin
 * @Date 12/19/2020 9:41 AM
 * @Version 1.0
 */
public class CreatCopyPathThreads {

    /*本递归复制函数具有检查并创建新目录的能力,*/

    /**
     * @param srcPath 可能是个目录,也可能是个文件
     * @param desPath 当srcPath 是一个目录的时候,desPath也必须是一个目录(1.约定该参数和srcPath是相同尾缀时;2.不用关心尾缀
     *                可能的参数组合包括:dir->dir;file->file;file->dir;(不可能是dir->file)
     * @throws IOException
     * @throws InterruptedException
     */
    static void copyPath(String srcPath, String desPath) throws IOException, InterruptedException {
        // System.out.println(count++);//testing(通过中途的内部打印来监视count的累计情况.)
        File srcPathFile = new File(srcPath);
        File desFile = new File(desPath);
        /* 如果源目标是个目录,则要保证目标目录存在: */
//        if (srcPathFile.isDirectory()&&!(new File(desPath)).exists()) {
//            (new File(desPath)).mkdir();//创建目录
//        }
        /*分析源路径*/
        if (srcPathFile.isDirectory()) {
            if (!(new File(desPath)).exists()) {
                desFile.mkdir();//创建目录
            }
            /*遍历当前目录下的子目录和文件(即各个条目)*/
            String[] filesPathString = srcPathFile.list();
            for (String subItem : filesPathString) {

                String absoluteSrcSubItemStr = srcPath + File.separator + subItem;
                String absoluteDesSubItemStr = desPath + File.separator + subItem;

          
                /*直接递归:*/
                copyPath(absoluteSrcSubItemStr, absoluteDesSubItemStr);
            }//endFor

        }//end if
        else {
            if (!desFile.exists()) {
                Files.copy(srcPathFile.toPath(), desFile.toPath());
            }
        }

    //test the class
    public static void main(String[] args) {
        try {
            //计时开始.
            long startTime = System.currentTimeMillis();
            copyPath(FileName.fileName11_1, "D://src");
            System.out.println("单线程目录拷贝完成,共耗时" + (System.currentTimeMillis() - startTime) + "毫秒");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

}//end class


posted @ 2024-08-23 09:24  xuchaoxin1375  阅读(22)  评论(0)    收藏  举报  来源