Android zip、tar+gz 压缩解压
16lz
2021-01-23
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(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.cgiimplementation '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); }
更多相关文章
- Error--->android工程导入找不到R文件
- 在AndroidManifest.xml文件中的android:windowSoftInputMode属性
- Gradle离线配置、.android、.AndroidStudio、.gradle、.m2缓存文
- Android 获取AndroidManifest.xml文件versionCode,versionName属
- Android客户端上传文件,C#服务端接收文件
- android 录音 Android 使用AudioRecord录音相关和音频文件的封装
- Android 实现文件(图片)上传
- android 读取raw文件下文件内容