package J20250805.demo01; import java.io.*; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * @author WanJl * @version 1.0 * @title FileCopyUtil * @description * **文件夹拷贝工具** * 需求: * - 设计`FileCopyUtil`类,包含`copyDirectory(String srcDir, String destDir)`方法 * - 使用多线程并发拷贝目录下的文件(子目录需递归处理) * - 利用`BufferedInputStream`和`BufferedOutputStream`提高 IO 效率 * - 统计总拷贝文件数和耗时,通过`System.out`输出结果 * @create 2025/8/5 */ public class FileCopyUtil { //线程安全的计数器,用来统计拷贝的文件总数 private final AtomicInteger copyFileCount=new AtomicInteger(); private ExecutorService executorService; /** * 拷贝目录的方法--在这里进行多线程操作 * @param srcDir 源目录路径 * @param destDir 目标目录路径 */ public void copyDirectory(String srcDir, String destDir) throws IOException, InterruptedException { File srcDirectory=new File(srcDir); File destDirectory=new File(destDir); //验证目录是否有效, if (!srcDirectory.exists()){ throw new FileNotFoundException("源目录不存在"+srcDir); } //记录开始时间 long startTime = System.currentTimeMillis(); //初始化线程池 int threadCount=Runtime.getRuntime().availableProcessors()*2; executorService= Executors.newFixedThreadPool(3); try{ //处理目录复制 copyDir(srcDirectory,destDirectory); //关闭线程池并且等待所有的任务都完成 executorService.shutdown(); if (!executorService.awaitTermination(1, TimeUnit.SECONDS)){ executorService.shutdownNow(); } }finally { if (!executorService.isTerminated()){ executorService.shutdownNow(); } } //计算耗时并且输出统计结果 long endTime = System.currentTimeMillis(); long time=endTime-startTime; System.out.println("目录拷贝完成"); System.out.println("总拷贝文件数:"+copyFileCount.get()); System.out.println("总耗时"+time+"毫秒"); } /** * 多线程中每个线程要执行的拷贝任务 * @param srcDir * @param destDir */ private void copyDir(File srcDir, File destDir) throws IOException,InterruptedException { //创建目标目录对象 if (!destDir.exists()&&!destDir.mkdirs()){ throw new IOException("无法创建目标目录"+destDir.getAbsolutePath()); } //获取源目录中的所有的文件和子目录 File[] files = srcDir.listFiles(); System.out.println(Arrays.toString(files)); if (files==null){ throw new IOException("无法访问目录内容"+srcDir.getAbsolutePath()); } //任务集合 List> futures=new ArrayList<>(); //处理目录中每个文件和文件夹 for (File file:files){ //在目标目录位置创建文件或子目录 File destFile = new File(destDir, file.getName()); if (file.isDirectory()){ //递归处理子目录 copyDir(file,destFile); }else { //提交文件拷贝任务到线程池 Future future=executorService.submit(()-> { try { copyFile(file,destFile); } catch (IOException e) { e.printStackTrace(); } }); //将任务放入集合 futures.add(future); } } //等所有的文件拷贝任务都完成后 for (Future future:futures){ try { future.get(); }catch (ExecutionException e) { //处理任务过程中如果出现问题则也抛出异常 Throwable cause = e.getCause(); if (cause instanceof IOException){ throw (IOException) cause; }else { throw new RemoteException("文件拷贝失败",cause); } } } } /** * 复制单个文件,使用缓冲流提高效率 * @param srcFile * @param destFile */ private void copyFile(File srcFile, File destFile) throws IOException { try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile))) { //字节缓冲区 byte[] buffer=new byte[8192]; int byteRead; //读取数据并且写入数据 while ((byteRead=bis.read(buffer))!=-1){ bos.write(buffer,0,byteRead); } //确保所有的数据都写入到磁盘 bos.flush(); //递增文件计数器 copyFileCount.incrementAndGet(); } } public static void main(String[] args) throws IOException, InterruptedException { FileCopyUtil fileCopyUtil=new FileCopyUtil(); fileCopyUtil.copyDirectory("D:\\myCode\\battle_city","D:\\MavenRepository111"); } }