Java implements the detailed code of compressing files or folders into zip

  • 2021-12-05 06:22:49
  • OfStack

Recently encountered a need to download zip compressed package requirements, so I found someone else on the Internet to write a good zip tool class. But after looking for many blogs, I always find bug. So I wrote a tool class myself.
The functions of this tool class are:
(1) You can compress files or folders
(2) At the same time, it supports compressing multi-level folders, and recursive processing is done in the tool
(3) If you encounter an empty folder, you can also compress it
(4) You can choose whether to keep the original directory structure. If not, all files run to the root directory of the compressed package, and the empty folder is directly discarded. Note: If you do not keep the original directory structure of the file, when you encounter a file with the same file name, it will fail to compress.
(5) Two methods of compressing files are provided in the code, one is the input parameter of folder path, and the other is the file list, which can be selected according to actual needs.

The code is directly on the following

1. Code


package com.tax.core.util; 

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.List;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

/**

 * ZipUtils

 * @author  ZENG.XIAO.YAN

 * @date    2017 Year 11 Month 19 Day   Afternoon 7:16:08

 * @version v1.0

 */

public class ZipUtils {

    

    private static final int  BUFFER_SIZE = 2 * 1024;

    /**

     *  Compress into ZIP  Method 1

     * @param srcDir  Compressed folder path  

     * @param out     Compressed file output stream 

     * @param KeepDirStructure   Whether to keep the original directory structure ,true: Preserve directory structure ; 

     *                          false: All files run to the root directory of the compressed package ( Note: Files with the same name may appear without preserving the directory structure , Compression fails )

     * @throws RuntimeException  Compression failure throws a runtime exception 

     */

    public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
           throws RuntimeException{

        

        long start = System.currentTimeMillis();

        ZipOutputStream zos = null ;

        try {

            zos = new ZipOutputStream(out);

            File sourceFile = new File(srcDir);

            compress(sourceFile,zos,sourceFile.getName(),KeepDirStructure);

            long end = System.currentTimeMillis();

            System.out.println(" Compression complete, time consuming: " + (end - start) +" ms");

        } catch (Exception e) {

            throw new RuntimeException("zip error from ZipUtils",e);

        }finally{

            if(zos != null){

                try {

                    zos.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

        

    }

    

    /**

     *  Compress into ZIP  Method 2

     * @param srcFiles  List of files to be compressed 

     * @param out            Compressed file output stream 

     * @throws RuntimeException  Compression failure throws a runtime exception 

     */

    public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {

        long start = System.currentTimeMillis();

        ZipOutputStream zos = null ;

        try {

            zos = new ZipOutputStream(out);

            for (File srcFile : srcFiles) {

                byte[] buf = new byte[BUFFER_SIZE];

                zos.putNextEntry(new ZipEntry(srcFile.getName()));

                int len;

                FileInputStream in = new FileInputStream(srcFile);

                while ((len = in.read(buf)) != -1){

                    zos.write(buf, 0, len);

                }

                zos.closeEntry();

                in.close();

            }

            long end = System.currentTimeMillis();

            System.out.println(" Compression complete, time consuming: " + (end - start) +" ms");

        } catch (Exception e) {

            throw new RuntimeException("zip error from ZipUtils",e);

        }finally{

            if(zos != null){

                try {

                    zos.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

    }

    

    

    /**

     *  Recursive compression method 

     * @param sourceFile  Source file 

     * @param zos        zip Output stream 

     * @param name        Compressed name 

     * @param KeepDirStructure   Whether to keep the original directory structure ,true: Preserve directory structure ; 

     *                          false: All files run to the root directory of the compressed package ( Note: Files with the same name may appear without preserving the directory structure , Compression fails )

     * @throws Exception

     */

    private static void compress(File sourceFile, ZipOutputStream zos, String name,

            boolean KeepDirStructure) throws Exception{

        byte[] buf = new byte[BUFFER_SIZE];

        if(sourceFile.isFile()){

            //  Toward zip Add to the output stream 1 A zip Entity, in the constructor name For zip The name of the file of the entity 

            zos.putNextEntry(new ZipEntry(name));

            // copy File to zip Output stream 

            int len;

            FileInputStream in = new FileInputStream(sourceFile);

            while ((len = in.read(buf)) != -1){

                zos.write(buf, 0, len);

            }

            // Complete the entry

            zos.closeEntry();

            in.close();

        } else {

            File[] listFiles = sourceFile.listFiles();

            if(listFiles == null || listFiles.length == 0){

                //  When you need to keep the original file structure , Need to process an empty folder 

                if(KeepDirStructure){

                    //  Handling of Empty Folders 

                    zos.putNextEntry(new ZipEntry(name + "/"));

                    //  No file, no need for a file copy

                    zos.closeEntry();

                }

                

            }else {

                for (File file : listFiles) {

                    //  Determine whether the original file structure needs to be preserved 

                    if (KeepDirStructure) {

                        //  Note: file.getName() You need to bring the name of the parent folder and add it before 1 Slash ,

                        //  Otherwise, the original file structure cannot be retained in the final compressed package , That is, all files run to the root directory of the compressed package 

                        compress(file, zos, name + "/" + file.getName(),KeepDirStructure);

                    } else {

                        compress(file, zos, file.getName(),KeepDirStructure);

                    }

                    

                }

            }

        }

    }

    public static void main(String[] args) throws Exception {

        /**  Test compression method 1  */

        FileOutputStream fos1 = new FileOutputStream(new File("c:/mytest01.zip"));

        ZipUtils.toZip("D:/log", fos1,true);

        /**  Test compression method 2  */

        List<File> fileList = new ArrayList<>();

        fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/jar.exe"));

        fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/java.exe"));

        FileOutputStream fos2 = new FileOutputStream(new File("c:/mytest02.zip"));

        ZipUtils.toZip(fileList, fos2);

    }

}

2. Considerations

When writing this tool class, some precautions are said as follows:
(1) Support to choose whether to keep the original file directory structure. If not, then empty folders need not be processed directly.
(1) When you encounter an empty folder, if you need to keep the directory structure, you can directly add an ZipEntry, but the name of this entry needs to be followed by a slash (/) to indicate that this is a directory.
(2) When recursive, the output stream of zip does not need to be closed, and the output stream of zip should be closed after calling the recursive method
(3) In recursion, if it is a folder and needs to keep the directory structure, when calling the method to compress its sub-files, it is necessary to add the name of the folder with a slash before the sub-file name, so that there are multi-level directories after compression.

3. How to use the tool class in an javaWeb project

The usage scenario of this tool class in web project is multi-file download, so I will simply say a case of downloading multiple excel tables.
The steps in the code are:
(1) Create a temporary folder
(2) Generate the files to be downloaded into the temporary folder
(3) When all files are generated, get HttpServletResponse. Get the downloaded header
(4) Call the method of the tool class and pass in the temporary folder path generated above and the output stream obtained by response; In this way, the zip package is downloaded
(5) Recursively delete the temporary folders and files generated above

The following is a code fragment of a sample code, not a complete code, just look at the steps in the code under 1


if(userList.size() > 0){

        /**  The following is the download zip Compressed package related process  */

        HttpServletRequest request = ServletActionContext.getRequest();

        FileWriter writer;

        /** 1. Create a temporary folder   */

        String rootPath = request.getSession().getServletContext().getRealPath("/");

        File temDir = new File(rootPath + "/" + UUID.randomUUID().toString().replaceAll("-", ""));

        if(!temDir.exists()){

            temDir.mkdirs();

        }

        /** 2. Generate files to be downloaded and store them in temporary folders  */

        //  Let's come directly here 10 For example, files with the same content, but this 10 File names cannot be the same 

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

            dataMap.put("userList", userList);

            Map<String, String> endMap = new HashMap<>();

            endMap.put("user", " Lao Wang ");

            endMap.put("time", "2017-10-10 10:50:55");

            dataMap.put("endMap", endMap);

            Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);

            cfg.setServletContextForTemplateLoading(ServletActionContext.getServletContext(), "/ftl");

            Template template = cfg.getTemplate("exportExcel.ftl");

            writer = new FileWriter(temDir.getPath()+"/excel"+ i +".xls");

            template.process(dataMap, writer);

            writer.flush();

            writer.close();

        }

        

        /** 3. Settings response Adj. header */

        HttpServletResponse response = ServletActionContext.getResponse();

        response.setContentType("application/zip");

        response.setHeader("Content-Disposition", "attachment; filename=excel.zip");  

        /** 4. Call the tool class, download zip Compressed package  */

        //  We don't need to preserve the directory structure here 

        ZipUtils.toZip(temDir.getPath(), response.getOutputStream(),false);

   /** 5. Delete temporary files and folders  */

        //  I didn't write recursion here, so I just deleted it 

        File[] listFiles = temDir.listFiles();

        for (int i = 0; i < listFiles.length; i++) {

            listFiles[i].delete();

        }

        temDir.delete();

    }

Related articles: