=Start=
缘由:
简单记录一下如何用Java对zip文件进行压缩和解压缩,尤其是如何将特定文件添加到一个已有的zip压缩包中(不用先解压,复制,然后重压缩的方式实现)。
正文:
参考解答:
压缩和解压缩特定文件的代码基本是从 Baeldung 这里拷贝过来的,直接往已有zip压缩包中添加文件是从官网中的示例中改的。
package com.example;
import java.io.*;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* @author ixyzero
* Created on 2022-05-09
*/
public class opZip {
public static void main(String[] args) {
String sourceFile = "new-test-docx.docx";
String zipFile = "test-output.zip";
String appendFile = "new-test-xlsx.xlsx";
String appendFile2 = "new-test-xlsx.rar";
String unzipDir = "unzipTest";
try {
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
zipFile(fileToZip, fileToZip.getName(), zipOut);
zipOut.close();
fos.close();
System.out.println("zip file success!");
addFileToZip(appendFile, zipFile);
addFileToZip2(appendFile2, zipFile);
unzipFile(zipFile, unzipDir);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// https://www.baeldung.com/java-compress-and-uncompress
private static void unzipFile(String filePath, String unzipDir) throws Exception {
File zipFile = new File(filePath);
File destDir = new File(unzipDir);
byte[] buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(destDir, zipEntry);
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
// fix for Windows-created archives
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}
// write file content
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
System.out.println("unzip file success!");
}
private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
if (fileToZip.isHidden()) {
return;
}
if (fileToZip.isDirectory()) {
if (fileName.endsWith("/")) {
zipOut.putNextEntry(new ZipEntry(fileName));
zipOut.closeEntry();
} else {
zipOut.putNextEntry(new ZipEntry(fileName + "/"));
zipOut.closeEntry();
}
File[] children = fileToZip.listFiles();
for (File childFile : children) {
zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
}
return;
}
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());
String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();
if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return destFile;
}
// work well, but only can add file not directory(files under dir can not be added)
// https://stackoverflow.com/questions/13787318/java-util-zip-replace-a-single-zip-file
public static void addFileToZip(String filePathStr, String zipFilePathStr) throws Exception {
Path myFilePath = Paths.get(filePathStr);
Path zipFilePath = Paths.get(zipFilePathStr);
try( FileSystem fs = FileSystems.newFileSystem(zipFilePath, null) ) {
Path fileInsideZipPath = fs.getPath(filePathStr.contains("/") ?
filePathStr.substring(filePathStr.lastIndexOf("/")) : "/"+filePathStr);
Files.copy(myFilePath, fileInsideZipPath); // fileInsideZipPath 字符串的内容其实可以任意设置
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return;
}
// do not work, until add fs.close()
public static void addFileToZip2(String filePathStr, String zipFilePathStr) throws Exception {
Path myFilePath = Paths.get(filePathStr);
Path zipFilePath = Paths.get(zipFilePathStr);
FileSystem fs = FileSystems.newFileSystem(zipFilePath, null);
Path fileInsideZipPath = fs.getPath(filePathStr.contains("/") ?
filePathStr.substring(filePathStr.lastIndexOf("/")) : "/"+filePathStr);
Files.copy(myFilePath, fileInsideZipPath);
fs.close(); // don't forget to add this after modify try-with-resources statement
return;
}
}
JDK7之后,Java多了个新的语法:try-with-resources语句,可以理解为是一个声明一个或多个资源的 try语句(用分号隔开),一个资源作为一个对象,并且这个资源必须要在执行完关闭的,try-with-resources语句确保在语句执行完毕后,每个资源都被自动关闭 。
参考链接:
Zipping and Unzipping in Java
https://www.baeldung.com/java-compress-and-uncompress
How to create Zip file in Java
https://mkyong.com/java/how-to-compress-files-in-zip-format/
Package java.util.zip
https://docs.oracle.com/javase/7/docs/api/java/util/zip/package-summary.html
Copying a File or Directory
https://docs.oracle.com/javase/tutorial/essential/io/copy.html
The try-with-resources Statement
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Java – Try with Resources
https://www.baeldung.com/java-try-with-resources
The try-with-resources statement
https://www.javatpoint.com/java-try-with-resources
java try-with-resource语句使用
https://www.jianshu.com/p/258c5ce1a2bd
深入理解 Java try-with-resource 语法糖
https://juejin.cn/post/6844903446185951240
=END=