Java Zip 磁盘与内存压缩实现

  Zip是常用的无损压缩算法实现,Java中提供了Zip的实现,本文针对磁盘上和内存中两种方式进行压缩和解压演示,演示只针对一层目录结构进行,多层目录只需递归操作进行即可。

  · Maven依赖

<dependency>
	<groupId>ant</groupId>
	<artifactId>ant</artifactId>
	<version>1.8.0</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>

  · 磁盘压缩和解压

  一般情况下,都是在磁盘上对文件进行操作,将所有文件存放在某一目录中,然后对目录进行压缩,工具类代码如下:

package com.arhorchin.securitit.compress.zip;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.FileUtils;

public class ZipDiskUtil {

    /**
     * 检索文件长度.
     */
    private static Integer lengthLimit = 3;

    /**
     * GBK字符集.
     */
    public static String GBK_CHARSET = "GBK";

    /**
     * ZIP文件压缩.
     * @param srcDirPath 待压缩文件目录.
     * @param tarFilePath 压缩后文件路径.
     * @return zip文件内容.
     * @throws Exception .
     */
    public static void zipCompress(String srcDirPath, String tarFilePath) throws Exception {
        // 1.压缩文件变量.
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        InputStream is = null;
        File srcDirFile = null;
        File[] filesArr = null;

        try {
            srcDirFile = new File(srcDirPath);
            fos = new FileOutputStream(new File(tarFilePath));
            filesArr = srcDirFile.listFiles();
            // 2.压缩文件变量初始化.
            zos = new ZipOutputStream(fos);
            // 3.压缩列表文件.
            for (File file : filesArr) {
                zos.putNextEntry(new ZipEntry(file.getName()));
                int len;
                byte[] buf = new byte[1024];
                is = new FileInputStream(file);
                while ((len = is.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
            }
        } finally {
            if (null != is)
                is.close();
            if (null != zos)
                zos.close();
            if (null != fos)
                fos.close();
        }
    }

    /**
     * ZIP文件压缩.低版本JDK时,解决条目中文文件名乱码问题.
     * @param srcDirPath 待压缩文件目录.
     * @param tarFilePath 压缩后文件路径.
     * @return zip文件内容.
     * @throws Exception .
     */
    public static void zipCompressCn(String srcDirPath, String tarFilePath) throws Exception {
        // 1.压缩文件变量.
        org.apache.tools.zip.ZipOutputStream zos = null;
        InputStream is = null;
        FileOutputStream fos = null;
        File srcDirFile = null;
        File[] filesArr = null;
        try {
            srcDirFile = new File(srcDirPath);
            filesArr = srcDirFile.listFiles();
            // 2.压缩文件变量初始化.
            fos = new FileOutputStream(new File(tarFilePath));
            zos = new org.apache.tools.zip.ZipOutputStream(fos);
            zos.setEncoding(GBK_CHARSET);
            // 3.压缩列表文件.
            for (File file : filesArr) {
                zos.putNextEntry(new org.apache.tools.zip.ZipEntry((file.getName())));
                int len;
                byte[] buf = new byte[1024];
                is = new FileInputStream(file);
                while ((len = is.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
            }
        } finally {
            if (null != is)
                is.close();
            if (null != fos)
                fos.close();
            if (null != zos)
                zos.close();
        }
    }

    /**
     * ZIP文件解压.
     * @param srcDirPath 待压缩文件目录.
     * @param tarFilePath 压缩后文件路径.
     * @return zip文件内容.
     * @throws Exception .
     */
    public static void zipDecompress(String srcFilePath, String tarDirPath) throws Exception {
        // 1.解压文件变量.
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        ZipInputStream zis = null;
        String tmpFileName = null;
        try {
            // 2.解压文件初始化.
            fis = new FileInputStream(new File(srcFilePath));
            bis = new BufferedInputStream(fis);
            zis = new ZipInputStream(bis);
            ZipEntry entry;
            // 3.搜索文件操作.
            while ((entry = zis.getNextEntry()) != null) {
                tmpFileName = entry.getName();
                if (tmpFileName.length() <= lengthLimit) {
                    continue;
                }
                FileUtils.writeByteArrayToFile(new File(tarDirPath + File.separator + tmpFileName), getEntryByte(zis));
            }
        } finally {
            if (null != fis)
                fis.close();
            if (null != zis)
                zis.close();
            if (null != bis)
                bis.close();
        }
    }

    /**
     * 获取条目byte[]字节 .
     * @param zis .
     * @return 条目字节.
     */
    public static byte[] getEntryByte(InflaterInputStream zis) {
        ByteArrayOutputStream bout = null;
        try {
            bout = new ByteArrayOutputStream();
            byte[] temp = new byte[1024];
            byte[] buf = null;
            int length = 0;
            while ((length = zis.read(temp, 0, 1024)) != -1) {
                bout.write(temp, 0, length);
            }
            buf = bout.toByteArray();
            return buf;
        } catch (IOException e) {
            return null;
        } finally {
            try {
                if (null != bout) {
                    bout.close();
                }
            } catch (Exception e) {
                return null;
            }
        }
    }

}

  测试类代码如下:

package com.arhorchin.securitit.com.compress;

import com.arhorchin.securitit.compress.zip.ZipDiskUtil;

public class ZipDiskUtilTester {

    public static void main(String[] args) throws Exception {
        ZipDiskUtil.zipCompress("C:/Users/Administrator/Downloads/个人文件/2020-07-13/files", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip");
        ZipDiskUtil.zipDecompress("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk");
    }

}

  · 内存压缩和解压

  在实际应用中,对应不同需求,可能需要生成若干文件,然后将其压缩。在某些应用中,文件较小、文件数量较少且较为固定,频繁与磁盘操作,会带来不必要的效率影响。此时,可以在内存中将文件进行压缩得到Zip文件,工具类代码如下:

package com.arhorchin.securitit.compress.zip;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipMemoryUtil {

    /**
     * 检索文件长度.
     */
    private static Integer lengthLimit = 3;

    /**
     * GBK字符集.
     */
    public static String GBK_CHARSET = "GBK";

    /**
     * ZIP文件压缩.
     * @param fileBytesMap 文件集合.
     * @return zip文件内容.
     * @throws Exception .
     */
    public static byte[] zipCompress(Map<String, byte[]> fileBytesMap) throws Exception {
        // 1.压缩文件变量.
        ByteArrayOutputStream baos = null;
        ZipOutputStream zos = null;
        try {
            // 2.压缩文件变量初始化.
            baos = new ByteArrayOutputStream();
            zos = new ZipOutputStream(baos);
            // 3.压缩列表文件.
            if (null != fileBytesMap && fileBytesMap.size() > 0) {
                for (Map.Entry<String, byte[]> file : fileBytesMap.entrySet()) {
                    zos.putNextEntry(new org.apache.tools.zip.ZipEntry(file.getKey()));
                    zos.write(file.getValue());
                }
            } else {
                baos = null;
            }
        } finally {
            if (null != baos)
                baos.close();
            if (null != zos)
                zos.close();
        }
        if (null == baos) {
            return null;
        }
        return baos.toByteArray();
    }

    /**
     * ZIP包转换,将ZIP包中指定类型文件重新打包. 支持中文目录版本,依赖ANT包,使用需谨慎.
     * @param fileBytesMap 文件集合.
     * @return zip文件内容.
     * @throws Exception .
     */
    public static byte[] zipCompressCn(Map<String, byte[]> fileBytesMap) throws Exception {
        // 1.压缩文件变量.
        ByteArrayOutputStream baos = null;
        org.apache.tools.zip.ZipOutputStream zos = null;
        try {
            // 2.压缩文件变量初始化.
            baos = new ByteArrayOutputStream();
            zos = new org.apache.tools.zip.ZipOutputStream(baos);
            zos.setEncoding(GBK_CHARSET);
            // 3.压缩列表文件.
            if (null != fileBytesMap && fileBytesMap.size() > 0) {
                for (Map.Entry<String, byte[]> file : fileBytesMap.entrySet()) {
                    zos.putNextEntry(new org.apache.tools.zip.ZipEntry(file.getKey()));
                    zos.write(file.getValue());
                }
            } else {
                baos = null;
            }
        } finally {
            if (null != baos)
                baos.close();
            if (null != zos)
                zos.close();
        }
        if (null == baos) {
            return null;
        }
        return baos.toByteArray();
    }
    
    /**
     * ZIP文件解压.
     * @param fileBytes zip数据.
     * @return 解压后的文件夹内容.
     * @throws Exception .
     */
    public static Map<String, byte[]> zipDecompress(byte[] fileBytes) throws Exception {
        // 1.解压文件变量.
        Map<String, byte[]> searchFileMap = null;
        byte[] searchFileBytes = null;
        ByteArrayInputStream bais = null;
        BufferedInputStream bis = null;
        ZipInputStream zis = null;
        String tmpFileName = null;
        try {
            // 2.解压文件初始化.
            searchFileMap = new HashMap<String, byte[]>();
            bais = new ByteArrayInputStream(fileBytes);
            bis = new BufferedInputStream(bais);
            zis = new ZipInputStream(bis);
            ZipEntry entry;
            // 3.搜索文件操作.
            while ((entry = zis.getNextEntry()) != null) {
                searchFileBytes = null;
                tmpFileName = entry.getName();
                if (tmpFileName.length() <= lengthLimit) {
                    continue;
                }
                searchFileBytes = getEntryByte(zis);
                searchFileMap.put(tmpFileName, searchFileBytes);
            }
        } finally {
            if (null != zis)
                zis.close();
            if (null != bis)
                bis.close();
            if (null != bais)
                bais.close();

        }
        return searchFileMap;
    }
    
    /**
     * 获取条目byte[]字节 .
     * @param zis .
     * @return 条目字节.
     */
    public static byte[] getEntryByte(InflaterInputStream zis) {
        ByteArrayOutputStream bout = null;
        try {
            bout = new ByteArrayOutputStream();
            byte[] temp = new byte[1024];
            byte[] buf = null;
            int length = 0;
            while ((length = zis.read(temp, 0, 1024)) != -1) {
                bout.write(temp, 0, length);
            }
            buf = bout.toByteArray();
            return buf;
        } catch (IOException e) {
            return null;
        } finally {
            try {
                if (null != bout) {
                    bout.close();
                }
            } catch (Exception e) {
                return null;
            }
        }
    }

}

  测试类代码如下:

package com.arhorchin.securitit.com.compress;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;

import com.arhorchin.securitit.compress.zip.ZipMemoryUtil;

public class ZipMemoryUtilTester {

    public static void main(String[] args) throws Exception {
        Map<String, byte[]> fileBytesMap = null;

        fileBytesMap = new HashMap<String, byte[]>();
        // 设置文件列表.
        File dirFile = new File("C:/Users/Administrator/Downloads/个人文件/2020-07-13/files");
        for (File file : dirFile.listFiles()) {
            fileBytesMap.put(file.getName(), FileUtils.readFileToByteArray(file));
        }

        byte[] memoryBytes = ZipMemoryUtil.zipCompress(fileBytesMap);
        FileUtils.writeByteArrayToFile(new File("C:/Users/Administrator/Downloads/个人文件/2020-07-13/memory.zip"), memoryBytes);
        
        fileBytesMap = ZipMemoryUtil.zipDecompress(memoryBytes);
        System.out.println(fileBytesMap.size());
    }

}

  · 总结

  1) 在小文件、文件数量较小且较为固定时,提倡使用内存压缩和解压方式。使用内存换时间,减少频繁的磁盘操作。

  2) 在大文件、文件数量较大时,提倡使用磁盘压缩和解压方式。过大文件对服务会造成过度的负载,磁盘压缩和解压可以缓解这种压力。

  3) JDK1.6及以下版本中,JDK提供的org.apache.tools.zip.*进行压缩时,对于中文条目名称处理会出现乱码,需要额外引用Ant包,使用其org.apache.tools.zip.*来解决这个问题。

猜你喜欢

转载自blog.csdn.net/securitit/article/details/107328107
今日推荐