piumnl
12/20/2016 - 1:44 PM

compress file or direcotry, but it can ignore the empty directory.

compress file or direcotry, but it can ignore the empty directory.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author: piumnl
 * @since: 2016-12-20
 */
public class ZipCompress {

  /**
   * 压缩文件
   * @param srcFile 源文件/夹
   * @param destFile 生成的目标文件
   */
  public static void compressDirectory(File srcFile, File destFile) {
    validate(srcFile, destFile);

    if (destFile.isDirectory()) {
      destFile = new File(destFile.getAbsolutePath() + ".zip");
    }

    try (FileOutputStream output = new FileOutputStream(destFile);
         CheckedOutputStream checked = new CheckedOutputStream(output, new CRC32());
         ZipOutputStream zipOutputStream = new ZipOutputStream(checked)) {

      compressDirectory(zipOutputStream, srcFile, "");
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 递归压缩
   * @param zipOutputStream 压缩的输出流
   * @param src 要压缩的目录,此处如果是空目录会被忽略掉
   * @param pre 前缀,重要!!!通过它分级
   * @throws IOException .
   */
  private static void compressDirectory(ZipOutputStream zipOutputStream, File src, String pre)
    throws IOException {
    File[] files = src.listFiles();
    for (File file : files != null ? files : new File[0]) {
      if (file.isDirectory()) {
        compressDirectory(zipOutputStream, file, pre + file.getName() + "/");
      } else {
        compressZipEntry(zipOutputStream, file, pre);
      }
    }
  }

  /**
   * 整理 生成 fileInputStream 对象并调用 compressZipEntry。
   * @param zipOutputStream  压缩的输出流
   * @param file 要压缩的文件
   * @param pre 前缀,重要!!!通过它分级
   */
  private static void compressZipEntry(ZipOutputStream zipOutputStream, File file, String pre) {
    try (FileInputStream fileInputStream = new FileInputStream(file)) {
      compressZipEntry(zipOutputStream, fileInputStream, pre + file.getName());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 压缩单个文件
   * @param srcFile 要压缩的文件
   * @param destFile 压缩后存放的文件
   */
  public static void compressFile(File srcFile, File destFile) {
    validate(srcFile, destFile);

    if (destFile.isDirectory()) {
      destFile = new File(destFile.getAbsolutePath() + ".zip");
    }

    try (FileInputStream input = new FileInputStream(srcFile);
         FileOutputStream output = new FileOutputStream(destFile);
         CheckedOutputStream checked = new CheckedOutputStream(output, new CRC32());
         ZipOutputStream zipOutputStream = new ZipOutputStream(checked)){

      compressZipEntry(zipOutputStream, input, srcFile.getName());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 底层压缩
   * @param output 压缩的输出流
   * @param input 要压缩的文件流
   * @param entryName 文件存放在zip中的名字
   */
  private static void compressZipEntry(ZipOutputStream output, FileInputStream input, String entryName) {
    try {
      ZipEntry entry = new ZipEntry(entryName);
      output.putNextEntry(entry);

      byte[] data = new byte[1024];
      int read;
      while ((read = input.read(data, 0, data.length)) != -1) {
        output.write(data, 0, read);
      }

      output.closeEntry();
    } catch (IOException e) {
      e.printStackTrace();
    }

  }

  /**
   * 验证文件的正确性。
   * @param srcFile 要压缩的文件
   * @param destFile 生成的目标文件
   */
  private static void validate(File srcFile, File destFile) {
    if (srcFile == null || destFile == null) {
      throw new NullPointerException();
    }

    if (destFile.getParentFile().getAbsolutePath().contains(srcFile.getAbsolutePath())) {
      throw new IllegalArgumentException("src can't contain the dest.");
    }
  }
}