当前位置: 首页 > 工具软件 > ZIP4J > 使用案例 >

Zip4j工具类学习笔记(帮助文档翻译)

逄嘉禧
2023-12-01

Zip4j工具类

Gitee: https://gitee.com/mirrors/zip4j

特征

  • 创建,添加,提取,更新,从Zip文件中删除文件
  • 支持流(ZipInputStream和ZipOutputStream)
  • 读/写受密码保护的Zip文件和流
  • 支持AES和Zip-Standard加密方法
  • 支持Zip64格式
  • 存储(无压缩)和放气压缩方法
  • 从拆分Zip文件创建或提取文件(例如:z01,z02,… zip)
  • 支持zip 中的Unicode文件名和注释* Progress Monitor- 集成到应用程序和面向用户的应用程序

帮助文档 : https://gitee.com/mirrors/zip4j/blob/master/README.md

Maven

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>2.6.1</version>
</dependency>

用法

创建其中包含单个文件的zip文件/将单个文件添加到现有zip中

new ZipFile("filename.zip").addFile("filename.ext");

   Or

new ZipFile("filename.zip").addFile(new File("filename.ext"));

创建包含多个文件的zip文件/将多个文件添加到现有zip中

new ZipFile("filename.zip").addFiles(Arrays.asList(new File("first_file"), new File("second_file")));

通过向其中添加文件夹来创建zip文件/将文件夹添加至现有zip中

new ZipFile("filename.zip").addFolder(new File("/users/some_user/folder_to_add"));

从v2.6开始,可以使用ExcludeFileFilter在将文件夹添加到zip时排除某些文件

ExcludeFileFilter excludeFileFilter = filesToExclude::contains;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setExcludeFileFilter(excludeFileFilter);
new ZipFile("filename.zip").addFolder(new File("/users/some_user/folder_to_add"), zipParameters);

从流创建zip文件/将流添加到现有zip

new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());

传递new ZipParameters(),如上面的例子中,将Zip4j使用默认参数拉链。请查看 ZipParameters以查看默认配置。

创建压缩方法库的zip文件/向压缩方法库的zip文件添加条目

默认情况下,Zip4j使用Deflate压缩算法来压缩文件。但是,如果您不想使用任何压缩(称为存储压缩),可以按照以下示例所示进行操作:

ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);

new ZipFile("filename.zip").addFile("fileToAdd", zipParameters);

您可以类似地将zip参数传递给所有其他示例,以创建一个STORE压缩的zip文件。

创建受密码保护的zip文件/使用密码保护将文件添加到现有zip中

AES加密
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
//下面的行是可选的。默认情况下使用AES 256。您可以覆盖它以使用AES128。AES192仅支持提取。
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); 

List<File> filesToAdd = Arrays.asList(
    new File("somefile"), 
    new File("someotherfile")
);

ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.addFiles(filesToAdd, zipParameters);
邮编标准加密:

代替AES,替换zipParameters.setEncryptionMethod(EncryptionMethod.AES);为 zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);。您可以省略该行以设置Aes Key强度。顾名思义,这仅适用于AES加密。

在以上所有示例中,您可以类似地传入具有适当密码配置的zip参数以创建受密码保护的zip文件

创建一个拆分的zip文件

如果要在大小超过特定限制时将zip文件拆分为多个文件,可以这样进行:

List<File> filesToAdd = Arrays.asList(
    new File("somefile"), 
    new File("someotherfile")
);

ZipFile zipFile = new ZipFile("filename.zip");
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, 10485760); //在此示例中使用10MB

传递new ZipParameters(),如上面的例子中,将Zip4j使用默认参数拉链。请查看 ZipParameters以查看默认配置。

压缩文件格式指定最小65536字节(64kb)作为拆分文件的最小长度。如果指定的值小于此值,Zip4j将引发异常。

要创建具有密码保护的拆分zip,请传递适当的ZipParameters,如下例所示:

ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);

List<File> filesToAdd = Arrays.asList(
    new File("somefile"), 
    new File("someotherfile")
);

ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, 10485760); //在此示例中使用10MB

Zip64格式

Zip64是一种zip功能,当zip文件的大小超过可以存储在4个字节中的最大值(即大于4,294,967,295字节)时,便支持zip文件。传统上,zip标头提供4个字节来存储文件大小。但是与几十年前相比,随着文件大小的增长,zip文件格式扩展了对文件大小的支持,通过添加额外的标头扩展了4个字节,这些标头使用8个字节作为文件大小(压缩和未压缩的文件大小)。此功能称为Zip64。

当Zip4j检测到zip文件超出此文件大小限制时,它将自动将其压缩为Zip64格式并添加适当的标头。您无需为Zip4j明确指定任何标志即可使用此功能

提取zip中的所有文件

new ZipFile("filename.zip").extractAll("/destination_directory");

提取受密码保护的zip中的所有文件

new ZipFile("filename.zip", "password".toCharArray()).extractAll("/destination_directory");

从zip提取单个文件

new ZipFile("filename.zip").extractFile("fileNameInZip.txt", "/destination_directory");

从zip提取文件夹(自v2.6.0起)

new ZipFile("filename.zip").extractFile("folderNameInZip/", "/destination_directory");

从受密码保护的zip提取单个文件

new ZipFile("filename.zip", "password".toCharArray()).extractFile("fileNameInZip.txt", "/destination_directory");

从v2.6.0开始:如果文件名表示目录,则zip4j将提取zip中属于该目录的所有文件。

从zip提取单个文件并为其赋予新文件名

下面的示例将从fileNameInZip.txtzip文件中提取文件到输出目录/destination_directory,并为文件命名newfileName.txt。如果没有新文件名的第三个参数,将使用与zip中的文件相同的名称,本例中为fileNameInZip.txt。如果要提取的文件是目录,newFileName则将参数用作目录名。

new ZipFile("filename.zip", "password".toCharArray()).extractFile("fileNameInZip.txt", "/destination_directory", "newfileName.txt");

获取zip文件中条目的输入流

ZipFile zipFile = new ZipFile("filename.zip");
FileHeader fileHeader = zipFile.getFileHeader("entry_name_in_zip.txt");
InputStream inputStream = zipFile.getInputStream(fileHeader);

现在,您可以使用此输入流从其中读取内容/将内容写入输出流。请注意,条目/文件名是相对于其所在目录的。如果entry_name_in_zip.txt位于zip的
“root_folder ”文件夹中,则可以使用zipFile.getFileHeader("root_folder/entry_name_in_zip.txt");

从zip文件中删除文件/条目

new ZipFile("filename.zip").removeFile("fileNameInZipToRemove");

如果fileNameInZipToRemove代表一个文件夹。该文件夹下的所有文件和文件夹也将被删除(自zip4j v2.5.0起有效。所有先前版本仅删除单个条目,即使它是文件夹)。

请注意,文件名是zip中根目录的相对名称。也就是说,如果要删除的文件存在于名为“ folder1”的文件夹中,而该文件夹又存在于名为“ root-folder”的文件夹中,则可以按以下步骤从zip中删除该文件:

new ZipFile("filename.zip").removeFile("root-folder/folder1/fileNameInZipToRemove");

如果要确定要删除的文件存在于zip文件中,或者如果不想在处理removeFileapi 时将文件名作为字符串处理,则可以使用其他重载方法,该方法采用FileHeader:

ZipFile zipFile = new ZipFile("someZip.zip");
FileHeader fileHeader = zipFile.getFileHeader("fileNameInZipToRemove");

if (fileHeader == null) {
  // file does not exist
}

zipFile.removeFile(fileHeader);

从zip4j v2.5.0开始,可以从zip文件中删除多个文件和文件夹。现在,您可以传递一个列表,如下面的代码所示:

ZipFile zipFile = new ZipFile("someZip.zip");
List<String> filesToRemove = Arrays.asList("file1.txt", "file2.txt", "some-folder/", "some-new-folder-1/somefile.pdf");

zipFile.removeFiles(filesToRemove);

上面的代码将删除file1.txt,file2.txt下的所有文件和文件夹some-folder(包括some-folder)和刚进入somefile.pdf的文件夹中some-new-folder-1。所有其他文件和文件夹在zip文件中均保持不变。

重命名zip文件中的条目

有三种方法可以使用zip4j重命名zip文件中的条目。一种方法是传递文件头和新文件名:

ZipFile zipFile = new ZipFile("sample.zip");
FileHeader fileHeader = zipFile.getFileHeader("entry-to-be-changed.pdf");
zipFile.renameFile(fileHeader, "new-file-name.pdf");

第二种方法是只传入要更改的文件名(而不是文件头)和新文件名。

new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");

也可以一次更改多个文件名。在这种情况下,您必须使用一个映射,该映射中条目的键是要更改的条目,而映射的值是新文件名:

Map<String, String> fileNamesMap = new HashMap<>();
fileNamesMap.put("firstFile.txt", "newFileFirst.txt");
fileNamesMap.put("secondFile.pdf", "newSecondFile.pdf");
fileNamesMap.put("some-folder/thirdFile.bin", "some-folder/newThirdFile.bin");
new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");

要修改文件夹内的条目名称,新文件名也应包含完整的父路径。例如,如果some-entry.pdf文件夹中包含按名称命名的条目,则some-folder/some-sub-folder/将该条目名称修改为some-new-entry.pdf:

new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-folder/some-sub-folder/new-entry.pdf");

如果缺少父路径路径,则该文件将放在zip文件的根目录中。在下面的示例中,文件重命名后,some-new-entry.pdf将存在于zip文件的根目录中,而不是位于some-folder/some-sub-folder/:

new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-new-entry.pdf");

这也提供了将条目“移动”到另一个文件夹的灵活性。下面的例子将移动 some-entry.pdf从some-folder/some-sub-folder/到folder-to-be-moved-to/sub-folder/该文件也将被重新命名为new-entry.pdf。要仅移动文件,请使用相同的文件名而不是新文件名。

new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "folder-to-be-moved-to/sub-folder/new-entry.pdf");

如果要修改的条目是目录,则该目录中的所有条目都将被重命名,以便所有这些条目都具有新的文件夹名称作为父文件夹。以zip格式,目录下的所有条目名称都将包含全名作为其文件名。例如,如果有一个由名称的条目filename.txt的目录里面directoryName,条目的文件名会directoryName/filename.txt。并且,如果目录名现在已更改为newDirectoryName,则其下的条目也将更改为newDirectoryName/filename.txt,因此提取zip文件时,该目录 filename.txt将位于下newDirectoryName。

压缩文件格式不允许修改拆分的zip文件,如果尝试重命名拆分的zip文件中的文件,zip4j将引发异常。

将拆分的zip文件合并为一个zip

这与创建拆分的zip文件相反,也就是说,此功能会将合并的zip文件(将多个文件拆分成一个zip文件)合并

new ZipFile("split_zip_file.zip").mergeSplitFiles(new File("merged_zip_file.zip"));

如果拆分的zip文件(在本例中split_zip_file.zip)不是拆分的zip文件,则此方法将引发异常

列出所有zip文件

List<FileHeader> fileHeaders = new ZipFile("zipfile.zip").getFileHeaders();
fileHeaders.stream().forEach(fileHeader -> System.out.println(fileHeader.getFileName()));

您可以从FileHeader与zip中每个文件/条目相对应的对象中获取所有其他信息。

检查zip文件是否受密码保护

new ZipFile("encrypted_zip_file.zip").isEncrypted();

检查zip文件是否为拆分的zip文件

new ZipFile("split_zip_file.zip").isSplitArchive();

设置zip文件的注释

new ZipFile("some_zip_file.zip").setComment("Some comment");

删除压缩文件的注释

new ZipFile("some_zip_file.zip").setComment("");

获取zip文件的评论

new ZipFile("some_zip_file.zip").getComment();

检查压缩文件是否有效

Note: This will only check for the validity of the headers and not the validity of each entry in the zip file.

new ZipFile("valid_zip_file.zip").isValidZipFile();

使用流

使用ZipOutputStream添加条目

import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ZipOutputStreamExample {

  public void zipOutputStreamExample(File outputZipFile, List<File> filesToAdd, char[] password,  
                                     CompressionMethod compressionMethod, boolean encrypt,
                                     EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength)
      throws IOException {

    ZipParameters zipParameters = buildZipParameters(compressionMethod, encrypt, encryptionMethod, aesKeyStrength);
    byte[] buff = new byte[4096];
    int readLen;

    try(ZipOutputStream zos = initializeZipOutputStream(outputZipFile, encrypt, password)) {
      for (File fileToAdd : filesToAdd) {

        //条目大小有,如果你想添加STORE压缩方法(不压缩)的条目设置
       //这是不需要deflate压缩
        if (zipParameters.getCompressionMethod() == CompressionMethod.STORE) {
          zipParameters.setEntrySize(fileToAdd.length());
        }

        zipParameters.setFileNameInZip(fileToAdd.getName());
        zos.putNextEntry(zipParameters);

        try(InputStream inputStream = new FileInputStream(fileToAdd)) {
          while ((readLen = inputStream.read(buff)) != -1) {
            zos.write(buff, 0, readLen);
          }
        }
        zos.closeEntry();
      }
    }
  }

  private ZipOutputStream initializeZipOutputStream(File outputZipFile, boolean encrypt, char[] password) 
      throws IOException {
    
    FileOutputStream fos = new FileOutputStream(outputZipFile);

    if (encrypt) {
      return new ZipOutputStream(fos, password);
    }

    return new ZipOutputStream(fos);
  }

  private ZipParameters buildZipParameters(CompressionMethod compressionMethod, boolean encrypt,
                                           EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength) {
    ZipParameters zipParameters = new ZipParameters();
    zipParameters.setCompressionMethod(compressionMethod);
    zipParameters.setEncryptionMethod(encryptionMethod);
    zipParameters.setAesKeyStrength(aesKeyStrength);
    zipParameters.setEncryptFiles(encrypt);
    return zipParameters;
  }
}

使用ZipInputStream提取文件

import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.LocalFileHeader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class ZipInputStreamExample {
  
  public void extractWithZipInputStream(File zipFile, char[] password) throws IOException {
    LocalFileHeader localFileHeader;
    int readLen;
    byte[] readBuffer = new byte[4096];

    InputStream inputStream = new FileInputStream(zipFile);
    try (ZipInputStream zipInputStream = new ZipInputStream(inputStream, password)) {
      while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
        File extractedFile = new File(localFileHeader.getFileName());
        try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
          while ((readLen = zipInputStream.read(readBuffer)) != -1) {
            outputStream.write(readBuffer, 0, readLen);
          }
        }
      }
    }
  }
}

使用进度监视器

ProgressMonitor使应用程序(尤其是面向用户)更易于集成Zip4j。显示进度非常有用(例如:更新进度栏,显示当前操作,显示正在处理的文件名等)。要使用ProgressMonitor,必须设置ZipFile.setRunInThread(true)。这将使对zip文件执行的所有操作均在后台线程中运行。然后,您可以访问ProgressMonitor Zipfile.getProgressMonitor()并获取当前正在执行的操作的详细信息以及完成的工作百分比等。以下是一个示例:

ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();

zipFile.setRunInThread(true);
zipFile.addFolder(new File("/some/folder"));

while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
  System.out.println("Percentage done: " + progressMonitor.getPercentDone());
  System.out.println("Current file: " + progressMonitor.getFileName());
  System.out.println("Current task: " + progressMonitor.getCurrentTask());

  Thread.sleep(100);
}

if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
  System.out.println("Successfully added folder to zip");
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
  System.out.println("Error occurred. Error message: " + progressMonitor.getException().getMessage());
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
  System.out.println("Task cancelled");
}

请注意,在上面的示例中,addFolder()几乎会立即将控件返回给调用方。然后,客户端代码可以执行循环,直到状态恢复为“就绪”为止,如上面的示例所示。

同样,ProgressMonitor可以与addFiles,removeFiles和等其他操作一起使用extractFiles。

实战

 /**
     * <per>
     * <p>本地构建Zip文件(文件的Zip打包)</p>
     * <p>
     * 1. 创建单个文件(目录)进行zip打包(单参)
     * 2. 将多个单文件(目录)添加到现有zip包中(多参):(目标zip,文件1,文件2...)</p>
     * <per/>
     * @param o is <code>String,File</code>
     * @return void
     * @throws
     * @Description
     * @author Liruilong
     * @Date 2020年08月19日  11:08:15
     **/
    public static void thisLocalityFileCreateZip(Object... o) {
        // 这是异常处理的一个工具接口
        exceptionUtil(() -> {
            File f = null;
            net.lingala.zip4j.ZipFile zipFile = null;
            for (int i = 0; i < o.length; i++) {
                if (o[i] instanceof String) {
                    f = new File((String) o[i]);
                } else if (o[i] instanceof File) {
                    f = (File) o[i];
                } else {
                    throw new IllegalArgumentException("参数异常");
                }
                if (i == 0) {
                    String fn = f.getName();
                    String fN = fn.substring(0, fn.indexOf(".") != -1 ? fn.indexOf(".") : fn.length());
                    String s = FILEPATH + fN + ".zip";
                    if (new File(s).exists()) {
                        cleanUtil(s);
                    }
                    zipFile = new net.lingala.zip4j.ZipFile(s);
                    zipFile.setRunInThread(true);
                }
                if (f.isDirectory()) {
                    zipFile.addFolder(f);
                } else if (f.isFile()) {
                    zipFile.addFile(f);
                }
            }
        }, "本地构建Zip文件异常");
    }
 类似资料: