Worship bosses = = = = = = = = > > > > > > > > > > the original: www.cnblogs.com/zeng1994/p/…
Recently, I met a need to download a ZIP compression package, so I found the next zip tool class written by others on the Internet. But I found a lot of blogs and always found bugs. So I wrote my own utility class.
The utility class has the following functions:
- (1) Can compress files, can also compress folders
- (2) at the same time to support the compression of multi-level folders, the tool internal recursive processing
- (3) Encountered empty folder, can also be compressed
- (4) You can choose whether to retain the original directory structure. If not, all files will be compressed to the root directory and empty folders will be discarded directly. Note: If you do not retain the original directory structure of the file, the compression will fail when encountering a file with the same file name.
- (5) The code provides two methods to compress files, one input parameter is the folder path, the other is the file list, you can choose the method according to the actual needs.
So let’s go straight to the code
Cooperate with (www.cnblogs.com/zagwk/p/140.) Download the zip package from the browser (the OutputStream parameter passed to the toZip method is response.getOutputStream())
package org.jeecg.modules.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
* @dateNovember 19, 2017 7:16:08 PM *@versionV1.0 * /
public class ZipUtils {
private static final int BUFFER_SIZE = 2 * 1024;
/** * to ZIP method 1 *@paramSrcDir Compressed folder path *@paramOut Indicates the output stream of compressed files@paramKeepDirStructure Specifies whether to keep the original directory structure. True: Indicates that the directory structure is kept. False: all files go to the root directory of the compressed package@throwsRuntimeException compression failure throws a RuntimeException */
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 completed, time:" + (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(); }}}}/** * to ZIP method 2 *@paramSrcFiles List of files to be compressed *@paramOut Indicates the output stream of compressed files@throwsRuntimeException compression failure throws a RuntimeException */
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 completed, time:" + (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 *@paramSourceFile sourceFile *@paramZos zip output stream *@paramName Compressed name *@paramKeepDirStructure Specifies whether to keep the original directory structure. True: Indicates that the directory structure is kept. False: all files go to the root directory of the compressed package@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()) {
// Add a zip entity to the zip output stream with the name of the file whose name is the zip entity in the constructor
zos.putNextEntry(new ZipEntry(name));
// Copy the file to the 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) {
// To preserve the original file structure, the empty folder needs to be processed
if (KeepDirStructure) {
// Empty folder handling
zos.putNextEntry(new ZipEntry(name + "/"));
// No file, no file copy is requiredzos.closeEntry(); }}else {
for (File file : listFiles) {
// Determine if you want to keep the original file structure
if (KeepDirStructure) {
// Note: file.getName() is preceded by the name of the parent folder with a slash,
// Otherwise, the original structure of the compressed package will not be retained, i.e., all files will be placed in 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); }}Copy the code
Two, matters needing attention
When writing this utility class, there are a few notes to note:
(1) Support to choose whether to retain the original file directory structure, if not, then empty folder directly do not need to deal with.
(1) When encountering an empty folder, if you want to preserve the directory structure, you can simply add a ZipEntry, but the name of this entry needs to be followed by a slash (/) to indicate that this is a directory.
(2) When recursing, there is no need to close the ZIP output stream. The closure of the ZIP output stream should be closed after calling the recursive method
(3) Recursively, if it is a folder and the directory structure needs to be retained, then when the method is called to compress its sub-file, the folder name needs to be added to the name of the sub-file with a slash, so that there can be multi-level directory after compression.
How do I use this tool class in a javaWeb project
The use of this utility class in web projects is multi-file downloads, so I’ll briefly describe the case of downloading multiple Excel spreadsheets.
The steps in the code are:
Create a temporary folder
(2) The files to be downloaded are generated into the temporary folder
(3) When all the files have been generated, get HttpServletResponse to get the header that sets the download
(4) Call the method of the tool class and pass in the temporary folder path generated above and the output stream obtained by response; This will download the ZIP package
(5) Recursively delete the temporary folders and files generated above
The following is a snippet of the sample code, not the complete code, but a brief look at the steps in the code
if(userList.size() > 0) {/** The following describes how to download the zip package */
HttpServletRequest request = ServletActionContext.getRequest();
FileWriter writer;
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 a file to be downloaded and store it in a temporary folder */
// Let's take 10 files with the same contents as an example, but the 10 files can not be the same
for (int i = 0; i < 10; i++) {
dataMap.put("userList", userList);
Map<String, String> endMap = new HashMap<>();
endMap.put("user"."Wang");
endMap.put("time"."The 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. Set the header */ for response
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/zip");
response.setHeader("Content-Disposition"."attachment; filename=excel.zip");
/** 4. Invoke the tool class to download the zip 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, just delete it
File[] listFiles = temDir.listFiles();
for (int i = 0; i < listFiles.length; i++) {
listFiles[i].delete();
}
temDir.delete();
}
Copy the code