案例:线程池 + 文件I/O流 + zip文件压缩 + 生成文件副本

学以致用!

线程 & 线程池 & 文件I/O流 & Zip文件压缩无需其他特别依赖。

功能:
    多线程完成批量文件(夹)(xls,txt,doc…)生成 & 压缩 & 下载(副本生成)

直接上源码:

1、程序入口(开启一个生成 & 压缩文件线程 & 生成zip副本)

import com.dongzi.GenerateZipFileThread;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class Main {
    
    
    public static void main(String[] args) throws InterruptedException, IOException {
    
    

        String fileDirPath = "D:/dongzi";
        String zipFileName = "D:/dongzi.zip";
        Map<String, Object> params = new HashMap<>();

        params.put("generateCount", 5);
        params.put("fileName", "新建文件");
        params.put("content", "文本内容");

        GenerateZipFileThread zipFileThread = new GenerateZipFileThread(fileDirPath, zipFileName, params);

        Thread thread = new Thread(zipFileThread);

        thread.start();
        thread.join(); // 等待线程执行完毕,直接生成一个zip压缩文件的副本

        downloadZip(zipFileName, "D:/dongzi-副本.zip");

    }

    /**
     * 读 zipFileName 压缩文件流 到 toZipFileName压缩文件中
     *
     * @param zipFileName   源文件
     * @param toZipFileName 目标文件
     */
    public static void downloadZip(String zipFileName, String toZipFileName) throws IOException {
    
    

        FileInputStream zipInStream = new FileInputStream(zipFileName);
        FileOutputStream toZipOutStream = new FileOutputStream(toZipFileName);

        byte[] b = new byte[1024];
        while ((zipInStream.read(b)) > -1) {
    
    
            toZipOutStream.write(b);
        }
        toZipOutStream.flush(); // 还可以将文件流刷新到其他地方
        // 切记关流
        toZipOutStream.close();
        zipInStream.close();
    }
}

2、开启线程生成文件 & 生成的文件进行zip压缩

package com.dongzi;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 生成 ZIP 压缩文件的线程
 * <pre>
 *     为什么实现Runnable?而不是继承Thread?
 *          在主进程中继承Thread的线程只能进行一次start(),
 *          调用第二次会出现异常(java.lang.IllegalStateException),而实现Runnable不会出现
 * </pre>
 */
public class GenerateZipFileThread implements Runnable {
    
    

    /**
     * 需要被压缩的源文件夹路径。eg: D:/dongzi
     */
    private final String fileDirPath;

    /**
     * 需要压缩成zip的文件名称。eg:D:/dongzi.zip
     */
    private final String zipFileName;

    /**
     * 参数:可自定
     */
    private final Map<String, Object> params;

    private final ExecutorService executorService;


    public GenerateZipFileThread(String fileDirPath, String zipFileName, Map<String, Object> params) {
    
    
        this.fileDirPath = fileDirPath;
        this.zipFileName = zipFileName;
        this.params = params;
        this.executorService = Executors.newFixedThreadPool(5);
    }

    /**
     * 重载 Runnable的run() 方法
     */
    @Override
    public void run() {
    
    

        if (params != null) {
    
    
            Integer generateCount = (Integer) params.get("generateCount"); // 假定需要生成到 fileDirPath 文件夹中的文件数量
            List<Future<String>> futureList = new ArrayList<>();

            for (int i = 0; i < generateCount; i++) {
    
    

                /*
                 * 为什么匿名实现Callable而不是 Runnable,因为Callable线程执行完毕后能返回执行结果
                 */
                int cnt = i;
                Future<String> future = executorService.submit(new Callable<String>() {
    
    
                    @Override
                    public String call() throws Exception {
    
    

                        // 文件夹
                        File fileDir = new File(fileDirPath);

                        // 文件夹不存在
                        if (!fileDir.exists()) {
    
    
                            // 创建新文件夹
                            boolean mkdir = fileDir.mkdir();
                            if (mkdir) {
    
    
                                System.out.println("already create new folder --> " + fileDir.getName());
                            }
                        }

                        // 需要在文件夹中创建的文件
                        String name = (String) params.get("fileName");
                        // 文件名
                        String fileName = name + "-" + cnt + ".txt";
                        // 文件生成到的路径. eg: D:/dongzi/文件-1.txt
                        String genFileName = fileDirPath + "/" + fileName;

                        File file = new File(genFileName);
                        // 需要被生成的文件已经存在
                        if (file.exists()) {
    
    
                            boolean delete = file.delete();
                            if (delete) {
    
    
                                System.out.println(file.getName() + " --> already exists. delete!");
                            }
                        }

                        // 文件内容
                        String content = (String) params.get("content");
                        FileOutputStream out = new FileOutputStream(file);
                        PrintWriter printWriter = new PrintWriter(out);
                        // 向文本写入内容
                        printWriter.write(content + "----" + cnt);

                        printWriter.flush();
                        printWriter.close();
                        out.close();
                        
                        // or todo other service
                        // ----- 至此 文件已经生成到对应文件夹
                        return null;
                    }
                });

                // 每提交一次线程
                futureList.add(future);
            }

            try {
    
    
                /*
                 * 线程全部提交完成之后,检查线程是否执行完毕:
                 *      执行完毕后将 fileDirPath 的文件夹 压缩成 zipFileName文件
                 */
                checkStatus(futureList, fileDirPath, zipFileName);
            } catch (InterruptedException | IOException e) {
    
    
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * @param futureList
     * @param fileDirPath
     * @param zipFileName
     */
    private void checkStatus(List<Future<String>> futureList, String fileDirPath, String zipFileName) throws InterruptedException, IOException {
    
    
        List<Future<String>> futures = new ArrayList<>();

        for (Future<String> future : futureList) {
    
    
            if (future.isDone()) {
    
    
                // 线程执行完成
                // future.get(); 客户获取线程执行结果
            } else {
    
    
                // 等待一段时间重新检查线程执行状态
                Thread.sleep(200);
                futures.add(future);
            }
        }
        if (!futures.isEmpty()) {
    
    
            checkStatus(futureList, fileDirPath, zipFileName);
        } else {
    
    
            // 线程全部执行完毕:将文件压缩

            // 需要压缩的源文件夹
            File sourceFileFolder = new File(fileDirPath);

            File zipFile = new File(zipFileName);

            FileOutputStream out = new FileOutputStream(zipFile);
            ZipOutputStream zipOutputStream = new ZipOutputStream(out);

            fileToZip(sourceFileFolder, sourceFileFolder.getName(), zipOutputStream);
            // 切记关流:如果不关流可能导致文件压缩损坏
            zipOutputStream.close();
            out.close();

            // todo: other
        }
    }

    /**
     * @param sourceFile 需要压缩的源文件夹
     * @param fileName   压缩文件名
     * @param zipOut     压缩文件输出流
     */
    public void fileToZip(File sourceFile, String fileName, ZipOutputStream zipOut) throws IOException {
    
    
        if (sourceFile.isDirectory()) {
    
    
            if (fileName.endsWith("/")) {
    
    
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
    
    
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }

            File[] childFiles = sourceFile.listFiles();
            // 遍历所有子文件
            assert childFiles != null;
            for (File childFile : childFiles) {
    
    
                fileToZip(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }

        // ...
        // 读文件,将文件压缩到zip文件中去
        FileInputStream fis = new FileInputStream(sourceFile);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
    
    
            zipOut.write(bytes, 0, length);
        }
        zipOut.flush();
        fis.close();

        if (this.executorService != null) {
    
    
            executorService.shutdown();
        }
    }
}

3、执行结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考链接:

java 文件夹打包成zip(带有嵌套的那种文件夹)

猜你喜欢

转载自blog.csdn.net/dongzi_yu/article/details/125773697