A preface

In project development, there is always the time to unzip files. For example, when a user downloads multiple files, the server can compress them into a single file (such as xx.zip or xx.rar). When users upload data, compressed files can be uploaded. The server decompresses each file and reads it.

Based on generality, the following methods are used to decompress files and package them into tool classes for daily development.

Ii Compressed File

Compressed files, as the name implies, compress one or more files into a single file. There are two ways to compress files. One is to compress all files to the same directory. In this way, pay attention to the problem of overwriting files with the same name. The other is to compress the file tree according to the original file tree structure, that is, the compressed file tree structure remains unchanged.

To compress a file, you use a class called ZipOutputStream.

2.1 Compressing Multiple Files

This method compresses all files into the same directory. Method passes in a list of files and a final file path name to compress to.

    /** * Compress multiple files in the same directory **@paramZipFileName Compressed file name *@paramFiles List of files to be compressed *@throwsIOException I/O exception */
    public static void zipMultipleFiles(String zipFileName, File... files) throws IOException {
        ZipOutputStream zipOutputStream = null;
        try {
            / / the output stream
            zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
            // Go through each file and output it
            for (File file : files) {
                zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
                FileInputStream fileInputStream = new FileInputStream(file);
                int readLen;
                byte[] buffer = new byte[1024];
                while((readLen = fileInputStream.read(buffer)) ! = -1) {
                    zipOutputStream.write(buffer, 0, readLen);
                }
                / / close the flowfileInputStream.close(); zipOutputStream.closeEntry(); }}finally {
            if (null! = zipOutputStream) {try {
                    zipOutputStream.close();
                } catch(IOException ex) { ex.printStackTrace(); }}}}Copy the code

TXT and infp1. TXT files from disk D to disk D. The compressed file name is my.zip.

    public static void main(String[] args) throws Exception {
        zipMultipleFiles("D:/my.zip".new File("D:/infp.txt"), new File("D:/infp1.txt"));
    }
Copy the code

2.2 Compressing files or file trees

This method compresses all files in the folder into a file in the original tree structure, and also supports the compression of a single file. The principle is also simple, nothing more than recursive traversal of the file tree each file, compression. It is important to note that the write path of each file is based on the relative path of the compressed file location.

package com.nobody.zip;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtils {

    /** * Zip files or folders (including all subdirectory files) **@paramSourceFile sourceFile *@paramFormat Format (ZIP or RAR) *@throwsIOException Exception information */
    public static void zipFileTree(File sourceFile, String format) throws IOException {
        ZipOutputStream zipOutputStream = null;
        try {
            String zipFileName;
            if (sourceFile.isDirectory()) { / / directory
                zipFileName = sourceFile.getParent() + File.separator + sourceFile.getName() + "."
                        + format;
            } else { // Single file
                zipFileName = sourceFile.getParent()
                        + sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf("."))
                        + "." + format;
            }
            // Compress the output stream
            zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
            zip(sourceFile, zipOutputStream, "");
        } finally {
            if (null! = zipOutputStream) {/ / close the flow
                try {
                    zipOutputStream.close();
                } catch(IOException ex) { ex.printStackTrace(); }}}}/** * recursively compress files **@paramFile Current file *@paramZipOutputStream Compressed output stream *@paramRelativePath relativePath *@throwsIOException I/O exception */
    private static void zip(File file, ZipOutputStream zipOutputStream, String relativePath)
            throws IOException {

        FileInputStream fileInputStream = null;
        try {
            if (file.isDirectory()) { // It is a folder
                // All files in the current folder
                File[] list = file.listFiles();
                if (null! = list) {// Calculate the current relative path
                    relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
                    // Compress each file recursively
                    for(File f : list) { zip(f, zipOutputStream, relativePath); }}}else { // Compress the file
                // Calculate the relative path of the file
                relativePath += (relativePath.length() == 0 ? "" : "/") + file.getName();
                // Write to a single file
                zipOutputStream.putNextEntry(new ZipEntry(relativePath));
                fileInputStream = new FileInputStream(file);
                int readLen;
                byte[] buffer = new byte[1024];
                while((readLen = fileInputStream.read(buffer)) ! = -1) {
                    zipOutputStream.write(buffer, 0, readLen); } zipOutputStream.closeEntry(); }}finally {
            / / close the flow
            if(fileInputStream ! =null) {
                try {
                    fileInputStream.close();
                } catch(IOException ex) { ex.printStackTrace(); }}}}public static void main(String[] args) throws Exception {
        String path = "D:/test";
        String format = "zip";
        zipFileTree(newFile(path), format); }}Copy the code

In the preceding example, all files in the test directory are compressed to the test.zip file in the same directory.

2.3 File Accessor compression

There’s an easier way, we don’t write our own recursive traversal. With the help of the Java native class SimpleFileVisitor, it provides several methods to access files, including visitFile, which is called for every file in the file tree (except folders). We simply write a class that inherits SimpleFileVisitor and override the visitFile method to write each file to a compressed file.

Of course, in addition to the visitFile method, it also has preVisitDirectory, postVisitDirectory, visitFileFailed and other methods, through the name of the method we also guess what meaning.

package com.nobody.zip;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/ * * *@Description
 * @Author Mr.nobody
 * @Date 2021/3/8
 * @Version1.0.0 * /
public class ZipFileTree extends SimpleFileVisitor<Path> {

    Zip output stream
    private ZipOutputStream zipOutputStream;
    / / the source directory
    private Path sourcePath;

    public ZipFileTree(a) {}

    /** * compressed directory and all subdirectory files **@paramSourceDir Source directory */
    public void zipFile(String sourceDir) throws IOException {
        try {
            // The compressed file is in the same directory as the source directory
            String zipFileName = sourceDir + ".zip";
            this.zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
            this.sourcePath = Paths.get(sourceDir);

            // Start traversing the file tree
            Files.walkFileTree(sourcePath, this);
        } finally {
            / / close the flow
            if (null! = zipOutputStream) { zipOutputStream.close(); }}}// This method is executed for each file traversed
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
        // Take the relative path
        Path targetFile = sourcePath.relativize(file);
        // Write to a single file
        zipOutputStream.putNextEntry(new ZipEntry(targetFile.toString()));
        byte[] bytes = Files.readAllBytes(file);
        zipOutputStream.write(bytes, 0, bytes.length);
        zipOutputStream.closeEntry();
        // Continue traversing
        return FileVisitResult.CONTINUE;
    }

    // The method that is called when each directory is traversed
    @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
            throws IOException {
        return super.preVisitDirectory(dir, attrs);
    }

    // Call a directory method after you have traversed all the files in the directory
    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        return super.postVisitDirectory(dir, exc);
    }

    // The method to call after traversing the file failed
    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
        return super.visitFileFailed(file, exc);
    }

    public static void main(String[] args) throws IOException {
        // Need to compress the source directory
        String sourceDir = "D:/test";
        / / compression
        newZipFileTree().zipFile(sourceDir); }}Copy the code

3 Decompressing files

Decompress the zip package and use the ZipInputStream class to read each file in the package, and then write the file properties to the corresponding path. For a file tree structure in the decompressed package, create a parent directory before writing a file to the file flow if the file is in a multilayer path after being read.

package com.nobody.zip;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/ * * *@DescriptionUnzip file utility class *@Author Mr.nobody
 * @Date 2021/3/8
 * @Version1.0.0 * /
public class ZipUtils {

    /** * unzip **@paramZipFilePath with unzip files *@paramDesDirectory Decompressed directory *@throws Exception
     */
    public static void unzip(String zipFilePath, String desDirectory) throws Exception {

        File desDir = new File(desDirectory);
        if(! desDir.exists()) {boolean mkdirSuccess = desDir.mkdir();
            if(! mkdirSuccess) {throw new Exception("Failed to create unzipped target folder"); }}/ / read inflow
        ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
        // Walk through each file
        ZipEntry zipEntry = zipInputStream.getNextEntry();
        while(zipEntry ! =null) {
            if (zipEntry.isDirectory()) { / / folder
                String unzipFilePath = desDirectory + File.separator + zipEntry.getName();
                // Create it directly
                mkdir(new File(unzipFilePath));
            } else { / / file
                String unzipFilePath = desDirectory + File.separator + zipEntry.getName();
                File file = new File(unzipFilePath);
                // Create a parent directory
                mkdir(file.getParentFile());
                // Write out the file stream
                BufferedOutputStream bufferedOutputStream =
                        new BufferedOutputStream(new FileOutputStream(unzipFilePath));
                byte[] bytes = new byte[1024];
                int readLen;
                while((readLen = zipInputStream.read(bytes)) ! = -1) {
                    bufferedOutputStream.write(bytes, 0, readLen);
                }
                bufferedOutputStream.close();
            }
            zipInputStream.closeEntry();
            zipEntry = zipInputStream.getNextEntry();
        }
        zipInputStream.close();
    }

    // If the parent directory does not exist
    private static void mkdir(File file) {
        if (null == file || file.exists()) {
            return;
        }
        mkdir(file.getParentFile());
        file.mkdir();
    }

    public static void main(String[] args) throws Exception {
        String zipFilePath = "D:/test.zip";
        String desDirectory = "D:/a"; unzip(zipFilePath, desDirectory); }}Copy the code

Four summarizes

  • In the process of decompressing files, the main operation is to read the flow, pay attention to abnormal processing, and close the flow.
  • In Web applications, file upload and download can be realized through the interface. Accordingly, we only need to write the compressed file into the response.getOutputStream() output stream.
  • When decompressing files, pay attention to empty folders.

This demo project has been uploaded to Github, if you need to download, welcome Star. Github.com/LucioChn/co…