1.介绍
本篇文章介绍,如何将文件压缩到存档中以及如何解压存档——所有这些都使用 Java 提供的核心库。
这些核心库是 java.util.zip 包的一部分——可以在其中找到所有与压缩和解压缩相关的实用程序。
2.压缩文件
看一个简单的操作——压缩单个文件。
对于示例,将一个名为 test1.txt 的文件压缩到一个名为compressed.zip 的存档文件中。
@Test
public void test1() throws IOException {
String sourceFile = "D:\\test1.txt";
//compressed.zip没有将会自动创建
FileOutputStream fos = new FileOutputStream("D:\\compressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
zipOut.close();
fis.close();
fos.close();
}
3.压缩多个文件
如何将多个文件压缩成一个 zip 文件。 将 test1.txt 和 test2.txt 压缩成 multiCompressed.zip:
@Test
public void test2() throws Exception {
List<String> srcFiles = Arrays.asList("D:\\test1.txt", "D:\\test2.txt");
FileOutputStream fos = new FileOutputStream("D:\\multiCompressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
for (String srcFile : srcFiles) {
File fileToZip = new File(srcFile);
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
zipOut.close();
fos.close();
}
4.压缩目录
接下来的示例演示,如何压缩整个目录。 将 zipTest 目录到 dirCompressed.zip :
@Test
public void test3() throws Exception {
String sourceFile = "D:\\zipTest";
FileOutputStream fos = new FileOutputStream("D:\\dirCompressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
zipFile(fileToZip, fileToZip.getName(), zipOut);
zipOut.close();
fos.close();
}
private 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();
}
注意:
- 为了压缩子目录,递归地遍历它们。
- 每次找到目录时,我们将其名称附加到后代 ZipEntry 名称以保存层次结构。
- 还要为每个空目录创建一个目录条目
5.解压缩文档
现在解压缩档案并提取其内容。
以下演示实例,把compressed.zip 解压缩到一个名为unzipTest 的新文件夹中。
public class UnzipFile {
public static void main(String[] args) throws IOException {
String fileZip = "D://compressed.zip";
File destDir = new File("E://unzipTest");
byte[] buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(destDir, zipEntry);
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("创建目录失败: " + newFile);
}
} else {
//修复 Windows 创建的目录
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("创建目录失败: " + parent);
}
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();
}
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("文件在目标目录之外: " + zipEntry.getName());
}
return destFile;
}
}
- 在 while 循环中,遍历每个 ZipEntry 并首先检查它是否是一个目录。 如果是,将使用 mkdirs() 方法创建目录; 否则,继续创建文件:
- 这里需要注意的是,在 else 分支上,首先检查文件的父目录是否存在。 这对于在 Windows 上创建的档案是必需的,其中根目录在 zip 文件中没有相应的条目。