批量文件打包下載

最近工作上有個需求,獲取批量文件,打包下載,如果源文件名中有重複,則需要重命名(加角標),如果壓縮後文件超過20兆,出於寬帶考慮,不下載,但給與提示.

思路. 先獲取所有文件,重命名,再壓縮存起來再判斷大小,滿足大小寫出流,不滿足給與提示

 

話不多說,如下代碼可以直接運行,賦有運行結果展示.

 

package com.fisher.cloud.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author Fisher
 */
@Controller
@RequestMapping("/test")
public class Test {

    private static final Logger logger = LoggerFactory.getLogger(Test.class);


    @RequestMapping(value = "/download", method = RequestMethod.GET)
    @ResponseBody
    public String downloadAttachment(HttpServletResponse response) throws IOException {
        //測試如下2個目錄下的文件打包,兩個目錄一樣的是爲了測試重命名問題
        File file1 = new File("D:\\IT\\參考資料\\文件導入導出");
        File file2 = new File("D:\\IT\\參考資料\\文件導入導出");
        File file3 = new File("D:\\IT\\參考資料\\文件下載模板導出方式");

        // 獲取所有文件
        List<File> fileList1 = Arrays.asList(file1.listFiles());
        List<File> fileList2 = Arrays.asList(file2.listFiles());
        List<File> fileList3 = Arrays.asList(file3.listFiles());
        List<File> totalFile = new ArrayList<>();
        if (fileList1.size() > 0) {
            for (File f : fileList1) {
                totalFile.add(f);
            }
        }
        if (fileList2.size() > 0) {
            for (File f : fileList2) {
                totalFile.add(f);
            }
        }
        if (fileList3.size() > 0) {
            for (File f : fileList3) {
                totalFile.add(f);
            }
        }
        try {
            // 壓縮文件 到"D:\IT\test",名字爲 "hello.zip
            File zipFile = this.zipFiles(totalFile, "D:\\IT\\test", "hello.zip");
            // 如果壓縮文件大於20兆,返回提示
            Integer maxSize = 20;
            if (maxSize * 1024 * 1024 < zipFile.length()) {
                return "壓縮包超過規定的20兆大小,限制下載";
            } else {
                // 將文件寫出
                writeOut(response, zipFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    // 批量文件壓縮成zip包
    public File zipFiles(List<File> fileList, String zipPath, String zipName) throws IOException {
        // 如果被壓縮文件中有重複,會重命名
        Map<String, String> namePathMap = getTransferName(fileList);
        File zipPathFile = new File(zipPath);
        // 文件夾不存在則創建
        if (!zipPathFile.exists()) {
            zipPathFile.mkdirs();
        }
        File zipFile = new File(zipPath + File.separator + zipName);
        if (!zipFile.exists()) {
            zipFile.createNewFile();
        }
        ZipOutputStream zos = null;
        BufferedInputStream bis = null;
        try {
            // 存放的目標文件
            zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile.getPath())));
            Set<String> keySet = namePathMap.keySet();
            ZipEntry zipEntry = null;
            for (String key : keySet) { // key是文件名,value是path
                // 指定源文件
                File sourceFile = new File(namePathMap.get(key));
                // 創建ZIP實體,並添加進壓縮包,指定壓縮文件中的文件名
                zipEntry = new ZipEntry(key);
                zos.putNextEntry(zipEntry);
                // 讀取待壓縮的文件並寫進壓縮包裏
                bis = new BufferedInputStream(new BufferedInputStream(new FileInputStream(sourceFile), 1024 * 10));
                byte[] bufs = new byte[1024 * 10];
                int read = 0;
                while ((read = (bis.read(bufs, 0, 1024 * 10))) != -1) {
                    zos.write(bufs, 0, read);
                }
                if (bis != null) {
                    bis.close();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 關閉流
            if (bis != null) {
                bis.close();
            }
            if (null != zos) {
                zos.close();
            }
        }
        return zipFile;

    }

    /**
     * 將文件寫出到流 【方法名】{方法的功能/動作描述}
     * @author Fisher
     * 
     * */
    private void writeOut(HttpServletResponse response, File zipFile) throws IOException {
        response.reset();
        response.setContentType("application/zip");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + zipFile.getName());
        OutputStream outputStream = response.getOutputStream();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(zipFile.getPath());
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.flush();
        } finally {
            if (null != fis) {
                fis.close();
            }
            if (null != outputStream) {
                outputStream.close();
            }
        }
    }

    // 計算壓縮包如果已存在重複的名稱,則在重複文件後面跟上數字 如: 文件(1).doc,文件(2).doc
    public Map<String, String> getTransferName(List<File> fileList) {
        if (fileList == null || fileList.size() == 0) {
            return new HashMap<String, String>();
        }
        // key存放文件名,value存放path
        Map<String, String> fileNameMap = new HashMap<>();
        List<String> fileNames = new ArrayList<>();
        for (File file : fileList) {
            // 獲取文件名
            String fileName = file.getName();
            int count = 0;

            for (String name : fileNames) {
                if (name != null && name.equals(fileName)) {
                    count++;
                }
            }
            fileNames.add(fileName);
            if (count > 0) {
                int lastIndex = fileName.lastIndexOf('.');
                String name = fileName.substring(0, lastIndex);
                String type = fileName.substring(lastIndex + 1, fileName.length());
                fileName = new StringBuilder().append(name).append("(").append(count).append(")").append(".")
                        .append(type).toString();
                fileNameMap.put(fileName, file.getPath());
            } else {
                fileNameMap.put(fileName, file.getPath());
            }
        }
        return fileNameMap;
    }

}
 

測試結果:相同名字會重複命名

 

超過20兆不下載,給與提示

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章