Android zip、tar+gz 压缩解压

package com.tool.util;

import androidx.annotation.Size;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**

  • 压缩工具类。

  • zip是将文件打包为zip格式的压缩文件。

  • gzip是将文件打包为tar.gz格式的压缩文件。

  • gzip只能对一个文件进行压缩,如果想压缩一大堆文件,就需要使用tar进行打包了。
    */
    public class CompressUtil {

    private static final byte[] ZIP_HEADER_1 = new byte[]{0x1F, (byte) 0x8B, 0x03, 0x04};
    private static final byte[] ZIP_HEADER_2 = new byte[]{0x1F, (byte) 0x8B, 0x05, 0x06};
    private static final int BUFF_SIZE = 1024;

    /**

    • 判断文件是否压缩
      */
      public static boolean isCompressed(@Size(4) byte[] data) {
      if (data == null || data.length < ZIP_HEADER_1.length) return false;
      byte[] header = Arrays.copyOf(data, ZIP_HEADER_1.length);
      return Arrays.equals(header, ZIP_HEADER_1) || Arrays.equals(header, ZIP_HEADER_2);
      }

    public static byte[] zip(byte[] data) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ZipOutputStream zip = new ZipOutputStream(baos);
    byte[] result = null;
    try {
    String name = FileUtil.genNameByDate();
    zip.putNextEntry(new ZipEntry(name));
    zip.write(data);
    zip.closeEntry();
    zip.flush();
    result = baos.toByteArray();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    zip.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return result;
    }

    public static byte[] unzip(byte[] data) {
    byte[] buffer = new byte[BUFF_SIZE];
    int len;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    ZipInputStream unzip = new ZipInputStream(bais);
    byte[] result = null;
    try {
    //这里的getNextEntry实际上是从byte数组里面读一段,如果没写这句,则后续解析失败
    ZipEntry zipEntry = unzip.getNextEntry();
    while ((len = unzip.read(buffer)) != -1) {
    baos.write(buffer, 0, len);
    }
    result = baos.toByteArray();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    unzip.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return result;
    }

    public static byte[] gzip(byte[] data) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream gzip = null;
    byte[] result = null;
    try {
    gzip = new GZIPOutputStream(baos);
    gzip.write(data);
    gzip.flush();
    //gzip这里有点问题,必须close之后再取数据,否则有遗漏
    gzip.close();
    gzip = null;
    result = baos.toByteArray();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    if (gzip != null) gzip.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return result;
    }

    public static byte[] ungzip(byte[] data) {
    byte[] buffer = new byte[BUFF_SIZE];
    int len;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    byte[] result = null;
    GZIPInputStream ungzip = null;
    try {
    ungzip = new GZIPInputStream(bais);
    while ((len = ungzip.read(buffer)) != -1) {
    baos.write(buffer, 0, len);
    }
    result = baos.toByteArray();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    if (ungzip != null) ungzip.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return result;
    }

    /**

    • ZIP压缩
    • @param file 待压缩的文件或文件夹
    • @param zos 压缩流
    • @param baseDir 相对压缩文件的相对路径
      */
      private static void zip(File file, ZipOutputStream zos, String baseDir) {
      if (file.isDirectory()) {
      File[] files = file.listFiles();
      for (File f : files) {
      zip(f, zos, baseDir + file.getName() + File.separator);
      }
      } else if (file.isFile()) {
      FileInputStream fis = null;
      try {
      fis = new FileInputStream(file);
      ZipEntry zipEntry = new ZipEntry(baseDir + file.getName());
      zos.putNextEntry(zipEntry);
      int len;
      byte[] buffer = new byte[BUFF_SIZE];
      while ((len = fis.read(buffer)) != -1) {
      zos.write(buffer, 0, len);
      }
      zos.closeEntry();
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      if (fis != null) fis.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      }

    /**

    • Zip压缩

    • @param srcFile 待压缩的文件或文件夹

    • @param dstDir 压缩至该目录,保持原文件名,后缀改为zip
      */
      public static void zip(File srcFile, String dstDir) {
      File file = new File(dstDir);
      //需要判断该文件存在,且是文件夹
      if (!file.exists() || !file.isDirectory()) file.mkdirs();

      String dstPath = dstDir + File.separator + srcFile.getName() + “.zip”;
      FileOutputStream fos = null;
      CheckedOutputStream cos = null;
      ZipOutputStream zos = null;
      try {
      fos = new FileOutputStream(dstPath);
      cos = new CheckedOutputStream(fos, new CRC32());
      zos = new ZipOutputStream(cos);
      zip(srcFile, zos, “”);
      zos.flush();
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      //关闭数据流的时候要先关闭外层,否则会报Stream Closed的错误
      if (zos != null) zos.close();
      if (cos != null) cos.close();
      if (fos != null) fos.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }

    /**

    • 解压
    • @param srcFile 待解压的文件
    • @param dstDir 解压到该目录,生成一个与原文件名相同的文件或文件夹
      */
      public static void unzip(File srcFile, String dstDir) {
      File file = new File(dstDir);
      //需要判断该文件存在,且是文件夹
      if (!file.exists() || !file.isDirectory()) file.mkdirs();
      ZipFile zipFile = null;
      FileOutputStream fos = null;
      InputStream is = null;
      try {
      //默认编码方式为UTF8
      zipFile = new ZipFile(srcFile);
      Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
      byte[] buffer = new byte[BUFF_SIZE];
      int len = 0;
      while (zipEntrys.hasMoreElements()) {
      ZipEntry zipEntry = zipEntrys.nextElement();
      String fileName = dstDir + File.separator + zipEntry.getName();
      File tmpFile = new File(fileName);
      File parent = tmpFile.getParentFile();
      if (!parent.exists()) parent.mkdirs();
      if (zipEntry.isDirectory()) {
      if (!tmpFile.exists()) tmpFile.mkdirs();
      } else {
      fos = new FileOutputStream(tmpFile);
      is = zipFile.getInputStream(zipEntry);
      while ((len = is.read(buffer)) != -1) {
      fos.write(buffer, 0, len);
      }
      is.close();
      is = null;
      fos.flush();
      fos.close();
      fos = null;
      }
      }
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      if (zipFile != null) zipFile.close();
      if (is != null) is.close();
      if (fos != null) fos.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }

    /**

    • tar打包,GZip压缩
    • @param file 待压缩的文件或文件夹
    • @param taos 压缩流
    • @param baseDir 相对压缩文件的相对路径
      */
      private static void tarGZip(File file, TarArchiveOutputStream taos, String baseDir) {
      if (file.isDirectory()) {
      File[] files = file.listFiles();
      for (File f : files) {
      tarGZip(f, taos, baseDir + file.getName() + File.separator);
      }
      } else {
      byte[] buffer = new byte[BUFF_SIZE];
      int len = 0;
      FileInputStream fis = null;
      TarArchiveEntry tarArchiveEntry = null;
      try {
      fis = new FileInputStream(file);
      tarArchiveEntry = new TarArchiveEntry(baseDir + file.getName());
      tarArchiveEntry.setSize(file.length());
      taos.putArchiveEntry(tarArchiveEntry);
      while ((len = fis.read(buffer)) != -1) {
      taos.write(buffer, 0, len);
      }
      taos.flush();
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      if (fis != null) fis.close();
      if (tarArchiveEntry != null) taos.closeArchiveEntry();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      }

    /**

    • tar打包,GZip压缩

    • @param srcFile 待压缩的文件或文件夹

    • @param dstDir 压缩至该目录,保持原文件名,后缀改为zip
      */
      public static void tarGZip(File srcFile, String dstDir) {
      File file = new File(dstDir);
      //需要判断该文件存在,且是文件夹
      if (!file.exists() || !file.isDirectory()) file.mkdirs();
      //先打包成tar格式
      String dstTarPath = dstDir + File.separator + srcFile.getName() + “.tar”;
      String dstPath = dstTarPath + “.gz”;

      FileOutputStream fos = null;
      TarArchiveOutputStream taos = null;
      try {
      fos = new FileOutputStream(dstTarPath);
      taos = new TarArchiveOutputStream(fos);
      tarGZip(srcFile, taos, “”);
      taos.flush();
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      //关闭数据流的时候要先关闭外层,否则会报Stream Closed的错误
      if (taos != null) taos.close();
      if (fos != null) fos.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }

      File tarFile = new File(dstTarPath);
      fos = null;
      GZIPOutputStream gzip = null;
      FileInputStream fis = null;
      try {
      //再压缩成gz格式
      fos = new FileOutputStream(dstPath);
      gzip = new GZIPOutputStream(fos);
      fis = new FileInputStream(tarFile);
      int len = 0;
      byte[] buffer = new byte[BUFF_SIZE];
      while ((len = fis.read(buffer)) != -1) {
      gzip.write(buffer, 0, len);
      }
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      if (fis != null) fis.close();
      //关闭数据流的时候要先关闭外层,否则会报Stream Closed的错误
      if (gzip != null) gzip.close();
      if (fos != null) fos.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }

      //删除生成的tar临时文件
      if (tarFile.exists()) tarFile.delete();
      }

    /**

    • GZip解压,tar解包
    • @param srcFile 待压缩的文件或文件夹
    • @param dstDir 压缩至该目录,保持原文件名,后缀改为zip
      */
      public static void untarGZip(File srcFile, String dstDir) {
      File file = new File(dstDir);
      //需要判断该文件存在,且是文件夹
      if (!file.exists() || !file.isDirectory()) file.mkdirs();
      byte[] buffer = new byte[BUFF_SIZE];
      FileInputStream fis = null;
      GzipCompressorInputStream gcis = null;
      TarArchiveInputStream tais = null;
      try {
      fis = new FileInputStream(srcFile);
      gcis = new GzipCompressorInputStream(fis);
      tais = new TarArchiveInputStream(gcis);
      TarArchiveEntry tarArchiveEntry;
      int len = 0;
      while ((tarArchiveEntry = tais.getNextTarEntry()) != null) {
      File f = new File(dstDir + File.separator + tarArchiveEntry.getName());
      if (tarArchiveEntry.isDirectory()) f.mkdirs();
      else {
      File parent = f.getParentFile();
      if (!parent.exists()) parent.mkdirs();
      FileOutputStream fos = new FileOutputStream(f);
      while ((len = tais.read(buffer)) != -1) {
      fos.write(buffer, 0, len);
      }
      fos.flush();
      fos.close();
      }
      }
      } catch (FileNotFoundException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      } finally {
      try {
      if(fis != null) fis.close();
      //关闭数据流的时候要先关闭外层,否则会报Stream Closed的错误
      if(tais != null) tais.close();
      if(gcis != null) gcis.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      }

在module的build.gradle中添加如下依赖

dependencies {
	……
	//提供tar+gzip的打包方式(TarArchive和GZipCompress)
	//http://commons.apache.org/proper/commons-compress/download_compress.cgi
	implementation 'org.apache.commons:commons-compress:1.18'
}

JUnit 测试如下(注意:文件路径需要改成自己的)

	@Test
    public void compress() {
        assertTrue(ZipOutputStream.class == getDelater());
    byte[] data = randomBytes(65535);
    byte[] zipData = CompressUtil.zip(data);
    byte[] unzipData = CompressUtil.unzip(zipData);
    assertArrayEquals(data, unzipData);

    byte[] gzipData = CompressUtil.gzip(data);
    byte[] ungzipData = CompressUtil.ungzip(gzipData);
    assertArrayEquals(data, ungzipData);

    String dir = "D:\\test";
    String path = "D:\\test\\Test Folder";
    String target = "D:\\test\\A\\B";
    CompressUtil.zip(new File(path), dir);
    CompressUtil.unzip(new File(path + ".zip"), target);

    CompressUtil.tarGZip(new File(path), dir);
    CompressUtil.untarGZip(new File(path + ".tar.gz"), target);
}

转载地址:
https://blog.csdn.net/chy555chy/article/details/89878563

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值