我是Java编程的初学者,目前正在编写一个必须能够压缩和解压缩.zip
文件的应用程序。我可以使用以下代码使用内置的Java zip功能以及Apache Commons IO库在Java中解压缩zip文件:
public static void decompressZipfile(String file, String outputDir) throws IOException {
if (!new File(outputDir).exists()) {
new File(outputDir).mkdirs();
}
ZipFile zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File entryDestination = new File(outputDir, entry.getName());
if (entry.isDirectory()) {
entryDestination.mkdirs();
} else {
InputStream in = zipFile.getInputStream(entry);
OutputStream out = new FileOutputStream(entryDestination);
IOUtils.copy(in, out);
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
}
我该如何从一个目录中创建一个zip文件,除了我已经在使用的库之外,不使用任何外部库?(Java标准库和Commons IO)
以下方法似乎可以成功地递归压缩目录:
public static void compressZipfile(String sourceDir, String outputFile) throws IOException, FileNotFoundException {
ZipOutputStream zipFile = new ZipOutputStream(new FileOutputStream(outputFile));
compressDirectoryToZipfile(sourceDir, sourceDir, zipFile);
IOUtils.closeQuietly(zipFile);
}
private static void compressDirectoryToZipfile(String rootDir, String sourceDir, ZipOutputStream out) throws IOException, FileNotFoundException {
for (File file : new File(sourceDir).listFiles()) {
if (file.isDirectory()) {
compressDirectoryToZipfile(rootDir, sourceDir + File.separator + file.getName(), out);
} else {
ZipEntry entry = new ZipEntry(sourceDir.replace(rootDir, "") + file.getName());
out.putNextEntry(entry);
FileInputStream in = new FileInputStream(sourceDir + file.getName());
IOUtils.copy(in, out);
IOUtils.closeQuietly(in);
}
}
}
正如在我的压缩代码片段中看到的,我使用IOUtils.copy()
来处理流数据传输。
我修复了上面的错误,它运行得很好。
public static void compressZipfile(String sourceDir, String outputFile) throws IOException, FileNotFoundException {
ZipOutputStream zipFile = new ZipOutputStream(new FileOutputStream(outputFile));
Path srcPath = Paths.get(sourceDir);
compressDirectoryToZipfile(srcPath.getParent().toString(), srcPath.getFileName().toString(), zipFile);
IOUtils.closeQuietly(zipFile);
}
private static void compressDirectoryToZipfile(String rootDir, String sourceDir, ZipOutputStream out) throws IOException, FileNotFoundException {
String dir = Paths.get(rootDir, sourceDir).toString();
for (File file : new File(dir).listFiles()) {
if (file.isDirectory()) {
compressDirectoryToZipfile(rootDir, Paths.get(sourceDir,file.getName()).toString(), out);
} else {
ZipEntry entry = new ZipEntry(Paths.get(sourceDir,file.getName()).toString());
out.putNextEntry(entry);
FileInputStream in = new FileInputStream(Paths.get(rootDir, sourceDir, file.getName()).toString());
IOUtils.copy(in, out);
IOUtils.closeQuietly(in);
}
}
}
看起来答案有点过时了。目前已更新为最新Java。同样在ZIP文件中,文件名将相对于给定的文件夹进行压缩。在最初的回答中,他们是绝对的,有完整的路径。
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class Zipper {
public static void compressFolder(String sourceDir, String outputFile) throws IOException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputFile))) {
compressDirectoryToZipFile((new File(sourceDir)).toURI(), new File(sourceDir), zipOutputStream);
}
}
private static void compressDirectoryToZipFile(URI basePath, File dir, ZipOutputStream out) throws IOException {
List<File> fileList = Files.list(Paths.get(dir.getAbsolutePath()))
.map(Path::toFile)
.collect(Collectors.toList());
for (File file : fileList) {
if (file.isDirectory()) {
compressDirectoryToZipFile(basePath, file, out);
} else {
out.putNextEntry(new ZipEntry(basePath.relativize(file.toURI()).getPath()));
try (FileInputStream in = new FileInputStream(file)) {
IOUtils.copy(in, out);
}
}
}
}
}
基于以上答案的全班ZipUtils
。
public final class ZipUtils {
private ZipUtils() {
}
// For testing
public static void main(String[] args) throws IOException {
compressFile(new File("./file.test"), new File("test1.zip"));
compressDirectory(new File("./test1"), new File("test2.zip"));
extractArchive(new File("./test2"), new File("test3.zip"));
}
public static void compressDirectory(File sourceDirectory, File zipFile) throws IOException {
Preconditions.checkState(sourceDirectory.exists(), "Source directory is not exists: %s", sourceDirectory);
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
compressDirectory(sourceDirectory.getAbsoluteFile(), sourceDirectory, out);
}
}
private static void compressDirectory(File rootDir, File sourceDir, ZipOutputStream out) throws IOException {
for (File file : Preconditions.checkNotNull(sourceDir.listFiles())) {
if (file.isDirectory()) {
compressDirectory(rootDir, new File(sourceDir, file.getName()), out);
} else {
String zipEntryName = getRelativeZipEntryName(rootDir, file);
compressFile(out, file, zipEntryName);
}
}
}
private static String getRelativeZipEntryName(File rootDir, File file) {
return StringUtils.removeStart(file.getAbsolutePath(), rootDir.getAbsolutePath());
}
public static void compressFile(File file, File zipFile) throws IOException {
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
compressFile(out, file, file.getName());
}
}
private static void compressFile(ZipOutputStream out, File file, String zipEntityName) throws IOException {
ZipEntry entry = new ZipEntry(zipEntityName);
out.putNextEntry(entry);
try (FileInputStream in = new FileInputStream(file)) {
IOUtils.copy(in, out);
}
}
public static void extractArchive(File targetDirectory, File zipFile) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
extractStream(targetDirectory, zis);
}
}
private static void extractStream(File targetDirectory, ZipInputStream zis) throws IOException {
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
extractEntry(targetDirectory, zis, zipEntry);
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
}
private static void extractEntry(File targetDirectory, ZipInputStream zis, ZipEntry zipEntry) throws IOException {
File newFile = newFile(targetDirectory, zipEntry);
if (zipEntry.isDirectory()) {
FileUtils.forceMkdir(newFile);
} else {
FileUtils.forceMkdirParent(newFile);
try (FileOutputStream fos = new FileOutputStream(newFile)) {
IOUtils.copy(zis, fos);
}
}
}
private static File newFile(File targetDirectory, ZipEntry zipEntry) throws IOException {
File targetFile = new File(targetDirectory, zipEntry.getName());
String targetDirPath = targetDirectory.getCanonicalPath();
String targetFilePath = targetFile.getCanonicalPath();
if (!targetFilePath.startsWith(targetDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return targetFile;
}
}