Java packages and downloads zip files for folders, including directory levels and files

Article directory

  • Preface
  • Controller
  • IService
  • ServiceImpl
  • FileUtil

Foreword

There is a function to upload files on the page. You can create a new directory and upload files under the directory, as shown in the figure:

Tips: Select the directory and click Package Download to export the folders and files in the directory into zips according to the hierarchy. If no task directory or file is selected, all directories and files will be compressed into zips according to the hierarchy

Controller

@ApiOperation(value = "Package download")
@GetMapping(value = "/downloadZip")
public void downloadZip(@ApiParam(name = "id", value= "project id/directory id/file id", required = true) @RequestParam(value = "id") Long id, HttpServletResponse response) throws Exception {<! -- -->
    projectMaterialsCatalogService.downloadZip(id, response);
}

IService

/**
 * Download package
 *
 * @param id directory id or file id
 * @param response
 * @throwsException
 */
void downloadZip(Long id, HttpServletResponse response) throws Exception;

ServiceImpl

/**
 * Download package
 *
 * @param id directory id or file id
 * @param response
 * @throwsException
 */
@Override
public void downloadZip(Long id, HttpServletResponse response) throws Exception {<!-- -->
    // First determine whether it is a project, and directly check the directory based on the project ID.
    LambdaQueryWrapper<ProjectMaterialsCatalog> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(ProjectMaterialsCatalog::getBusinessId, id);
    queryWrapper.eq(ProjectMaterialsCatalog::getIsDeleted, "0");
    List<ProjectMaterialsCatalog> projectMaterialsCatalogs = baseMapper.selectList(queryWrapper);

    //Generated ZIP file path
    String zipFilePath = "";
    //Generated temporary folder hierarchy
    String temFolderPath = "";
    // If it is a project ID, all directory data needs to be packaged and downloaded.
    if (CollectionUtils.isNotEmpty(projectMaterialsCatalogs)) {<!-- -->
        //Multiple level 1 folders are placed under the temporary folder, with the current project ID as the folder
        temFolderPath = filesPath + File.separator + id;
        for (ProjectMaterialsCatalog catalog : projectMaterialsCatalogs) {<!-- -->
            //Create the directory first and then create the file
            String catalogName = catalog.getCatalogName();
            // First generate the folder containing hierarchical structure based on the directory
            genCatalog(catalog, temFolderPath + File.separator + catalogName);
        }
        zipFilePath = temFolderPath + ".zip";
        //Compress the generated folder
        FileUtil.folderToZip(zipFilePath, temFolderPath, true);
    } else {<!-- -->
        // Then determine whether it is a directory or a file
        ProjectMaterialsCatalog catalog = baseMapper.selectById(id);
        if (catalog != null) {<!-- -->
            //Create the directory first and then create the file
            String catalogName = catalog.getCatalogName();
            temFolderPath = filesPath + File.separator + catalogName;
            zipFilePath = temFolderPath + ".zip";
            // First generate the folder containing hierarchical structure based on the directory
            genCatalog(catalog, temFolderPath);
            //Compress the generated folder
            FileUtil.folderToZip(zipFilePath, temFolderPath, true);
        } else {<!-- -->
            // The description is a file, package this file into zip
            ProjectMaterialsFiles fileInfo = projectMaterialsFilesMapper.selectById(id);
            // Get file path
            String filePath = filesPath + File.separator + fileInfo.getFilePath();
            // Get the file name prefix
            String prefix = cn.hutool.core.io.FileUtil.getPrefix(fileInfo.getFileName());
            //Generated ZIP file path
            zipFilePath = filesPath + File.separator + prefix + ".zip";
            //Compress the file
            List<File> fileList = new ArrayList<>();
            fileList.add(new File(filePath));
            FileUtil.fileToZip(zipFilePath, fileList);
        }
    }
    try {<!-- -->
        // Download the generated file zip
        File zipFile = new File(zipFilePath);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFile.getName(), "UTF-8"));
        InputStream in = new FileInputStream(zipFile);
        // Obtain the output stream - the output stream obtained through response is used to write content to the client
        ServletOutputStream out = response.getOutputStream();
        //File copy code
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) != -1) {<!-- -->
            out.write(buffer, 0, len);
        }
        out.flush();
        out.close();
        in.close();
        response.flushBuffer();
    } catch (IOException e) {<!-- -->
        throw new RuntimeException(e);
    } finally {<!-- -->
        // Delete compressed package
        cn.hutool.core.io.FileUtil.del(zipFilePath);
        //Delete the created folder
        if (StringUtils.isNotBlank(temFolderPath)) {<!-- -->
            cn.hutool.core.io.FileUtil.del(temFolderPath);
        }
    }
}

/**
 * Recursively generate folders and files
 *
 * @param rootCatalog
 * @param catalogPath
 */
public void genCatalog(ProjectMaterialsCatalog rootCatalog, String catalogPath) throws Exception {<!-- -->
    File file = new File(catalogPath);
    if (!file.exists()) {<!-- -->
        file.mkdirs();
    }
    // Determine whether there are files in the directory
    List<ProjectMaterialsFiles> filesList = projectMaterialsFilesMapper.getFileByCatalogId(rootCatalog.getId());
    if (CollectionUtils.isNotEmpty(filesList)) {<!-- -->
        // Loop to create files in this directory
        for (ProjectMaterialsFiles f : filesList) {<!-- -->
            File sourceFile = new File(filesPath + File.separator + f.getFilePath());
            //The source file does not exist
            if (!sourceFile.exists()) {<!-- -->
                continue;
            }
            File destFile = new File(catalogPath + File.separator + f.getFileName());
            Files.copy(sourceFile, destFile);
        }
    }
    LambdaQueryWrapper<ProjectMaterialsCatalog> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(ProjectMaterialsCatalog::getIsDeleted, "0");
    queryWrapper.eq(ProjectMaterialsCatalog::getParentId, rootCatalog.getId());
    List<ProjectMaterialsCatalog> catalogList = baseMapper.selectList(queryWrapper);
    if (CollectionUtils.isNotEmpty(catalogList)) {<!-- -->
        for (ProjectMaterialsCatalog catalog : catalogList) {<!-- -->
            catalogPath + = File.separator + catalog.getCatalogName();
            genCatalog(catalog, catalogPath);
        }
    }
}

FileUtil

/**
 * Compress the folder into ZIP
 *
 * @param zipFileName Generate compressed folder path
 * @param sourceFileName The file path to be compressed
 * @param KeepDirStructure Whether to retain the original directory structure, true: retain the directory structure;
 * false: All files run to the root directory of the compressed package (note: files with the same name may appear if the directory structure is not retained, and the compression will fail)
 * @throws RuntimeException If compression fails, a runtime exception will be thrown
 */
public static Boolean folderToZip(String zipFileName, String sourceFileName, boolean KeepDirStructure) {<!-- -->
Boolean result = true;
long start = System.currentTimeMillis();//Start
ZipOutputStream zos = null;
try {<!-- -->
FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
zos = new ZipOutputStream(fileOutputStream);
File sourceFile = new File(sourceFileName);
compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
long end = System.currentTimeMillis();//End
System.out.println("Compression completed, time taken: " + (end - start) + " milliseconds");
} catch (Exception e) {<!-- -->
result = false;
e.printStackTrace();
} finally {<!-- -->
if (zos != null) {<!-- -->
try {<!-- -->
zos.close();
} catch (IOException e) {<!-- -->
e.getStackTrace();
}
}
}
return result;
}

/**
 * Compress files into ZIP to compress multiple files at once
 *
 * @param srcFiles list of files to be compressed
 * @param zipFileName compressed file output
 * @throws RuntimeException If compression fails, a runtime exception will be thrown
 */
public static void fileToZip(String zipFileName, List<File> srcFiles) throws Exception {<!-- -->
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {<!-- -->
FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
zos = new ZipOutputStream(fileOutputStream);
for (File srcFile : srcFiles) {<!-- -->
compress(srcFile, zos, srcFile.getName(), true);
}
long end = System.currentTimeMillis();
System.out.println("Compression completed, time taken: " + (end - start) + " milliseconds");
} 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 retain the original directory structure, true: retain the directory structure;
 * false: All files run to the root directory of the compressed package (note: files with the same name may appear if the directory structure is not retained, and the compression will fail)
 * @throwsException
 */
public static void compress(File sourceFile, ZipOutputStream zos, String name,
boolean KeepDirStructure) throws Exception {<!-- -->

if (sourceFile.isFile()) {<!-- -->
//Add a zip entity to the zip output stream. The name in the constructor is the name of the file of the zip entity.
zos.putNextEntry(new ZipEntry(name));
// copy the file to the zip output stream
int len;
byte[] buf = new byte[1024];
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 retain the original file structure, you need to process the empty folder
if (KeepDirStructure) {<!-- -->
//Handling of empty folders
zos.putNextEntry(new ZipEntry(name + "/"));
// There is no file, no copy of the file is required
zos.closeEntry();
}
} else {<!-- -->
for (File file : listFiles) {<!-- -->
// Determine whether the original file structure needs to be retained
if (KeepDirStructure) {<!-- -->
// Note: file.getName() needs to be preceded by the name of the parent folder plus a slash.
// Otherwise, the original file structure cannot be retained in the final compressed package, that is: all files will go to the root directory of the compressed package.
compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
} else {<!-- -->
compress(file, zos, file.getName(), KeepDirStructure);
}
}
}
}
}