如何在Java中压缩文件和文件夹?

请看下面的代码。

public void startCompress(String path,String fileName,String outputLocation,int compressType,int filSize) throws Exception { System.out.println("Input Location: "+path); System.out.println("Output Location: "+outputLocation); System.out.println(compressType); byte[] bs=new byte[filSize]; System.out.println(filSize); FileOutputStream fos=new FileOutputStream(outputLocation+"/test.zip"); System.out.println(fos.toString()); ZipOutputStream zos=new ZipOutputStream(fos); ZipEntry ze = new ZipEntry(fileName); zos.putNextEntry(ze); FileInputStream inputStream=new FileInputStream(path); int len; while((len=inputStream.read(bs))>0){ zos.write(bs, 0, len); } inputStream.close(); zos.closeEntry(); zos.close(); } 

在上面的代码中,我们使用java.util.zip包压缩文件。 但我们有一个问题。 也就是说,如果我们选择多个文件,则只压缩一个文件。 如果我们选择一个文件夹,压缩就不起作用了。

如何修复此问题以压缩文件,文件,文件夹,文件夹甚至嵌套文件夹? Java zip包支持.zip,.tar,.tarGz和tarZ。 所以解决方案不应该只限于.zip扩展。

java的zip库不能用于以更简单的方式压缩文件夹 – 压缩此文件夹。

如果输入是文件夹或文件,则需要自己进行测试。 如果是文件 – 将其添加到zip。 如果是文件夹 – 迭代文件夹并将每个文件添加到zip。 对于子文件夹来说是一样的。 要向Zip添加多个文件,您需要为每个文件创建ZipEntry。

您可以尝试这个适用于我的代码:

 public static void zip(File directory, File zipfile) throws IOException { URI base = directory.toURI(); Deque queue = new LinkedList(); queue.push(directory); OutputStream out = new FileOutputStream(zipfile); Closeable res = out; try { ZipOutputStream zout = new ZipOutputStream(out); res = zout; while (!queue.isEmpty()) { directory = queue.pop(); for (File kid : directory.listFiles()) { String name = base.relativize(kid.toURI()).getPath(); if (kid.isDirectory()) { queue.push(kid); name = name.endsWith("/") ? name : name + "/"; zout.putNextEntry(new ZipEntry(name)); } else { zout.putNextEntry(new ZipEntry(name)); copy(kid, zout); zout.closeEntry(); } } } } finally { res.close(); } } 

从这个答案更新,修复了每个文件被添加到它自己的目录的问题。 也更好地支持Windows资源管理器。

 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class Test { public static void main(String agrs[]) { ZipUtils appZip = new ZipUtils(); appZip.zipIt(new File(source directory), new File(dest zip)); } public static class ZipUtils { private final List fileList; private List paths; public ZipUtils() { fileList = new ArrayList<>(); paths = new ArrayList<>(25); } public void zipIt(File sourceFile, File zipFile) { if (sourceFile.isDirectory()) { byte[] buffer = new byte[1024]; FileOutputStream fos = null; ZipOutputStream zos = null; try { // This ensures that the zipped files are placed // into a folder, within the zip file // which is the same as the one been zipped String sourcePath = sourceFile.getParentFile().getPath(); generateFileList(sourceFile); fos = new FileOutputStream(zipFile); zos = new ZipOutputStream(fos); System.out.println("Output to Zip : " + zipFile); FileInputStream in = null; for (File file : this.fileList) { String path = file.getParent().trim(); path = path.substring(sourcePath.length()); if (path.startsWith(File.separator)) { path = path.substring(1); } if (path.length() > 0) { if (!paths.contains(path)) { paths.add(path); ZipEntry ze = new ZipEntry(path + "/"); zos.putNextEntry(ze); zos.closeEntry(); } path += "/"; } String entryName = path + file.getName(); System.out.println("File Added : " + entryName); ZipEntry ze = new ZipEntry(entryName); zos.putNextEntry(ze); try { in = new FileInputStream(file); int len; while ((len = in.read(buffer)) > 0) { zos.write(buffer, 0, len); } } finally { in.close(); } } zos.closeEntry(); System.out.println("Folder successfully compressed"); } catch (IOException ex) { ex.printStackTrace(); } finally { try { zos.close(); } catch (IOException e) { e.printStackTrace(); } } } } protected void generateFileList(File node) { // add file only if (node.isFile()) { fileList.add(node); } if (node.isDirectory()) { File[] subNote = node.listFiles(); for (File filename : subNote) { generateFileList(filename); } } } } } 

这是我使用新的java.nio包的解决方案。 只需调用zipDir,即可获得该目录的路径。 它将在同一位置创建一个zip文件,但称为.zip

 private static Path buildPath(final Path root, final Path child) { if (root == null) { return child; } else { return Paths.get(root.toString(), child.toString()); } } private static void addZipDir(final ZipOutputStream out, final Path root, final Path dir) throws IOException { try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path child : stream) { Path entry = buildPath(root, child.getFileName()); if (Files.isDirectory(child)) { addZipDir(out, entry, child); } else { out.putNextEntry(new ZipEntry(entry.toString())); Files.copy(child, out); out.closeEntry(); } } } } public static void zipDir(final Path path) throws IOException { if (!Files.isDirectory(path)) { throw new IllegalArgumentException("Path must be a directory."); } BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path.toString() + ".zip")); try (ZipOutputStream out = new ZipOutputStream(bos)) { addZipDir(out, path.getFileName(), path); } }