如何用Java压缩文件夹

时间:2020-01-09 10:35:31  来源:igfitidea点击:

在"如何用Java压缩文件"一文中,我们了解了如何用Java压缩单个文件或者多个文件,但是我们可能还需要用Java压缩文件夹,在压缩文件夹的同时还保留文件夹树结构。这篇文章展示了如何用Java压缩文件夹,其中zip归档文件包含整个树结构(文件和子目录)。

在Java中压缩文件夹的选项

为了压缩包含所有子文件夹和文件的文件夹,本文提供了两个选项。

  • 使用Files.walkFileTree方法–使用此方法,我们可以递归访问文件树中的所有文件。 FileVisitor接口的实现提供给Files.walkFileTree方法,以访问文件树中的每个文件。 Java 7及更高版本提供此选项。参见示例。
  • 通过使用java.io.File类中的listFiles()方法自己提供代码来递归读取文件夹中的文件。参见示例。

使用的目录结构

此处显示的用于压缩Java文件夹的Java程序使用以下目录结构。

在父文件夹中有一个子文件夹,子文件夹有两个文件,一个文件存储在父文件夹中。压缩档案应保留相同的树结构。

使用Files.walkFileTree方法在Java中压缩文件夹

此方法的参数之一是FileVisitor接口。我们确实需要根据需要提供此接口的实现。 FileVisitor界面有四种方法,要压缩文件夹,我们确实需要实现其中两种。

  • preVisitDirectory –在访问目录条目之前调用。通过实现此方法,我们可以在zip存档中创建访问文件夹。
  • visitFile –在要访问的文件上调用。通过实现此方法,我们可以将每个访问的文件添加到zip存档中。
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipOutputStream;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;

public class ZipFolder {
  public static void main(String[] args) {
    // Source folder
    final String SOURCE_DIR = "F:/theitroad/Parent";
    // creating the name of the zipped archive
    String ZIP_DIR = SOURCE_DIR.concat(".zip");
    zipFolderStructure(SOURCE_DIR, ZIP_DIR);
  }
    
  private static void zipFolderStructure(String sourceFolder, String zipFolder){
    // Creating a ZipOutputStream by wrapping a FileOutputStream
    try (FileOutputStream fos = new FileOutputStream(zipFolder); 
         ZipOutputStream zos = new ZipOutputStream(fos)) {
      Path sourcePath = Paths.get(sourceFolder);
      // Walk the tree structure using WalkFileTree method
      Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>(){
        @Override
        // Before visiting the directory create the directory in zip archive
        public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
          // Don't create dir for root folder as it is already created with .zip name 
          if(!sourcePath.equals(dir)){
            System.out.println("Directory- " + dir);
            zos.putNextEntry(new ZipEntry(sourcePath.relativize(dir).toString() + "/"));                  
            zos.closeEntry();    
          }
          return FileVisitResult.CONTINUE;
        }
        @Override
        // For each visited file add it to zip entry
        public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
          System.out.println("File Name- " + sourcePath.relativize(file).toString());
          zos.putNextEntry(new ZipEntry(sourcePath.relativize(file).toString()));
          Files.copy(file, zos);
          zos.closeEntry();
          return FileVisitResult.CONTINUE;
        }});
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

输出:

Directory- F:\theitroad\Parent\Child
File Name- Child\hello.txt
File Name- Child\Project.docx
File Name- Test.txt

通过递归列出文件来压缩Java文件夹

在代码中,首先创建一个父文件夹中所有文件和文件夹的列表。为了在目录中使用文件列表,使用java.io.File类的listFiles()方法。

在列表中拥有此文件夹树结构后,便可以遍历该列表以创建zip存档。对于列表中的每个迭代元素,请检查它是目录还是文件
如果是目录,则只需在zip归档文件中添加目录的名称。
如果是文件,则添加名称以及文件内容。

public class ZippingFolder {
  List fileList = new ArrayList();
  public static void main(String[] args) {	
    // Source folder
    final String ROOT_DIR = "F:/theitroad/Parent";
    // creating the name of the zipped archive
    String ZIP_DIR = ROOT_DIR.concat(".zip");
    ZippingFolder zippingFolder = new ZippingFolder();
    // get the list of the whole folder structure
    zippingFolder.getListOfFiles(new File(ROOT_DIR));
    zippingFolder.zipTreeStructure(ROOT_DIR, ZIP_DIR);
  }
	
  private void zipTreeStructure(String ROOT_DIR, String zipDir){
    final int BUFFER = 1024;
    BufferedInputStream bis = null;
    ZipOutputStream zos = null;
    try{
      // Creating ZipOutputStream by wrapping FileOutputStream
      FileOutputStream fos = new FileOutputStream(zipDir);
      zos = new ZipOutputStream(fos);
      // iterating the folder tree structure
      for(File file : fileList){
        // If directory
        if(file.isDirectory()){
          // add the directory name as zipentry
          ZipEntry ze = new ZipEntry(file.getName()+"/");             
          zos.putNextEntry(ze);
          zos.closeEntry();
        }
        // If file
        else{
          FileInputStream fis = new FileInputStream(file);
          bis = new BufferedInputStream(fis, BUFFER);                
          ZipEntry ze = new ZipEntry(getFileName(ROOT_DIR, file.toString()));                   
          zos.putNextEntry(ze);
          byte data[] = new byte[BUFFER];
          int count;
          while((count = bis.read(data, 0, BUFFER)) != -1) {
            zos.write(data, 0, count);
          }
          bis.close();
          zos.closeEntry();
        }               
      }                
           
    }catch(IOException ioExp){
      ioExp.printStackTrace();
    } finally{
      try {
        zos.close(); 
        if(bis != null)
          bis.close();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }  
    }
  }
  // Method to get the folder tree structure
  private void getListOfFiles(File source){
    File[] fileNames = source.listFiles();
    for(File file : fileNames){
      if(file.isDirectory()){
        fileList.add(file);
        // recursive call to go through the subdirectory structure
        getListOfFiles(file);
      }else{
        fileList.add(file);
      }
    }
  }
    
  // To get the relative file path 
  private String getFileName(String ROOT_DIR, String filePath){
    String name = filePath.substring(ROOT_DIR.length() + 1, filePath.length());
    return name;
  }
}