美文网首页
Java压缩方法分析

Java压缩方法分析

作者: 码上就说 | 来源:发表于2018-08-22 15:01 被阅读44次

前言:了解一门技术,会用是基础,接下来了解其中的原理,以及多种方法比较,并且发现某种方法的痛点,最好能够根据痛点切实提出一些解决方法,才能说真正掌握这门技术了。

一、压缩与解压缩的原理

压缩有有损压缩和无损压缩两种,本文只探讨无损压缩。

二、如何实现压缩与解压缩

ZipUtils.java

package com.miuidaemon.tools.zip;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
    
    /**
     * 压缩单个文件
     * @param srcFolder  源文件文件夹
     * @param srcFileName  源文件文件名
     * @param destFilePath  压缩之后文件全路径
     * @throws IOException
     */
    public static void zipSingleFile(String srcFilePath, String destFolder, String destFileName) throws IOException {
        File destFile = new File(destFolder);
        if (!destFile.exists()) {
            destFile.mkdir();
        }
        if (destFile.exists()) {
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
            zipFile(srcFilePath, zos);
            zos.close();
        }
    }
    
    /**
     * 压缩多个文件
     * @param srcFiles
     * @param destFolder
     * @param destFileName
     * @throws IOException
     */
    public static void zipMultipleFiles(String[] srcFiles, String destFolder, String destFileName) throws IOException {
        File destFile = new File(destFolder);
        if (!destFile.exists()) {
            destFile.mkdir();
        }
        if (destFile.exists()) {
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
            for(String srcFile : srcFiles) {
                zipFile(srcFile, zos);
            }
            zos.close();
        }
    }
    
    /**
     * 压缩某个目录
     * @param srcFolder 输入的目录字符串最后不带  /
     * @param destFolder
     * @param destFileName
     * @throws IOException
     */
    public static void zipDir(String srcFolder, String destFolder, String destFileName) throws IOException {
        long start = System.currentTimeMillis();
        System.out.println("ZipDir begin : ");
        File destFile = new File(destFolder);
        if (!destFile.exists()) {
            destFile.mkdir();
        }
        if (destFile.exists()) {
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
            ZipDirFunction(srcFolder, zos);
            zos.close();
        }
        System.out.println("ZipDir end : " + (System.currentTimeMillis() - start) / 1000  + " s");
    }
    
    /**
     * 不能出现重名的文件
     * @param srcFilePath
     * @param zos
     * @throws IOException
     */
    public static void ZipDirFunction(String srcFilePath, ZipOutputStream zos) throws IOException {
        File srcFile = new File(srcFilePath);
        if (srcFile.isDirectory()) {
            String[] children = srcFile.list();
            for (int i=0;i<children.length;i++) {
                ZipDirFunction(srcFilePath + File.separator + children[i], zos);
            }
            return;
        }
        System.out.println("ZipDirFunction srcFilePath = " + srcFilePath);
        zipFile(srcFilePath, zos);
    }
    
    /**
     * 通用压缩类
     * @param srcFilePath
     * @param zos
     * @throws IOException
     */
    public static void zipFile(String srcFilePath, ZipOutputStream zos) throws IOException {
        zos.setLevel(Deflater.BEST_COMPRESSION);
        File entryFile = new File(srcFilePath);
        ZipEntry ze = new ZipEntry(entryFile.getName());
        zos.putNextEntry(ze);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(entryFile));
    
        byte[] buffer = new byte[1024];
        int count = -1;
        bis.read();
    
        while((count = bis.read(buffer)) != -1) {
            zos.write(buffer, 0, count);
        }
    
        bis.close();
        zos.closeEntry();
    }
    
    /**
     * 解压缩
     * @param srcFilePath  需要解压的文件路径
     * @param destFolder   解压之后存储文件的路径   这个文件路径后面需要加 /
     * @throws IOException
     */
    public static void unZipFile(String srcFilePath, String destFolder) throws IOException {
        File filePath = new File(destFolder);
        if (!filePath.exists()) {
            filePath.mkdir();
        }
        long start = System.currentTimeMillis();
        System.out.println("unZipFile beigin : " + start);
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(srcFilePath)));
        ZipEntry zipEntry = zis.getNextEntry();
        while(zipEntry != null) {
            String fileName = zipEntry.getName();
            File newFile = new File(destFolder + fileName);
            if (zipEntry.isDirectory()) {
                
            }
            
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
            
            byte[] buffer = new byte[1024];
            int count = -1;
            while((count = zis.read(buffer)) > 0) {
                bos.write(buffer, 0, count);
            }
            
            bos.close();
            System.out.println("unZip file name = " + zipEntry.getName());
            zipEntry = zis.getNextEntry();
        }
        zis.closeEntry();
        zis.close();
        
        System.out.println("unZipFile end : " + (System.currentTimeMillis() - start) / 1000 + " s");
    }
}

测试文件

ZipTest.java

package com.miuidaemon.tools.zip;

import java.io.IOException;

public class ZipTest {
    
    private static final String FOLDER = "/home/jeffmony/xiaomi/tools/oom_dir/tmp/";
    private static final String FILENAME = "com.android.systemui-2018-08-08-172249-oom.hprof";
    
    public static void main(String[] args) {
        try {
//          ZipUtils.zipSingleFile(FOLDER + FILENAME, FOLDER + "LITIANPENG/", "helloworld.zip");
//          String[] fileList = new String[] {FOLDER + "test.hprof", FOLDER + "test2.hprof"};
//          ZipUtils.zipMultipleFiles(fileList, FOLDER + "testHu/", "hello.zip");
            
//          ZipUtils.zipDir("/home/jeffmony/xiaomi/tools/oom_dir/tmp", "/home/jeffmony/xiaomi/tools/oom_dir/", "testhello.zip");
            
            ZipUtils.unZipFile("/home/jeffmony/xiaomi/tools/oom_dir/testhello.zip", "/home/jeffmony/xiaomi/tools/oom_dir/hello2/");
        } catch (IOException e) {
            System.out.print("Exception Message : " + e.getMessage());
        }
        
        
    }
}

三、压缩与解压缩的效率问题

3.1 压缩时不能有相同的文件名

ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof/com.android.systemui-2018-08-08-175700-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/hello.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/test2.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/test.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/LITIANPENG/helloworld.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test2.hprof
Exception Message : duplicate entry: test2.hprof

出现了相同的文件,两个test2.hprof文件,压缩的时候要注意一点,为什么会这样,下面会解释。

3.2 压缩时间

ZipDir begin : 
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof/com.android.systemui-2018-08-08-175700-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/hello.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/LITIANPENG/helloworld.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test2.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/litianpeng/com.android.systemui-2018-08-08-172249-oom.hprof.zip
ZipDir end : 20 s

压缩目录的时间如上,压缩之前之后的大小是:


压缩前后大小比较.png

压缩之前是:72M
压缩之后是:30M
压缩时间是:20s

3.3 解压缩时间

unZipFile beigin : 1533781329441
unZip file name = com.android.systemui-2018-08-08-175700-oom.hprof
unZip file name = com.android.systemui-2018-08-08-175700-oom.hprof.zip
unZip file name = hello.zip
unZip file name = helloworld.zip
unZip file name = com.android.systemui-2018-08-08-172249-oom.hprof
unZip file name = test2.hprof
unZip file name = test.hprof
unZip file name = com.android.systemui-2018-08-08-172249-oom.hprof.zip
unZipFile end : 0 s

解压缩的时间确实很快。

3.4 解压缩之后目录结构改变

但是也存在一个问题,如下:
压缩之前的文件结构是:


压缩之前文件结构.png

压缩之后文件结构是:


压缩之后文件结构.png
虽然文件数量没有减少,但是文件结构已经被破坏,这也就解释了之前压缩的时候为什么不能有重名的文件。

四、拓展提高

4.1 其他压缩方法

4.2 压缩方法痛点

4.2.1 压缩出现同名文件失败
4.2.2 解压之后文件结构改变

未完待续。

相关文章

  • Java压缩方法分析

    前言:了解一门技术,会用是基础,接下来了解其中的原理,以及多种方法比较,并且发现某种方法的痛点,最好能够根据痛点切...

  • ECC/SM2 公钥(点)压缩与还原

    ECC/SM2 公钥(点)压缩方法,64字节公钥压缩成33字节公钥。 一、C 二、Java Java基于bcpro...

  • 【JVM系列4】new Object()到底占用几个字节,看完这

    前言 上一篇我们分析了Java虚拟机方法执行流程及方法重载和方法重写原理,并分析了方法的调用过程及原理,Java虚...

  • 图片压缩之优化篇

    之前曾经对Android中图片中的压缩方式进行分析和总结。详见图片压缩篇。基本涵盖了基础的压缩方法和思路。但是在实...

  • tar解压失败:gzip: stdin: not in gzip

    解决方法:去掉z参数,使用 tar -xvf 解压正常 原因分析:1、压缩文件被人为的改过名称,比如:最初压缩的并...

  • Android Apk 优化:PNG图片压缩对比分析

    第118期:Android Apk 优化:PNG图片压缩对比分析 [英] 深入理解 Android和Java中的引...

  • Java图片压缩处理

    网页中某些图片大的时候,图片会加载慢,这时候需要对图片进行压缩处理,Java有对图片进行压缩处理的方法。 整体思路...

  • ProGuard-压缩-混淆

    ProGuard是一个Java类文件压缩器、优化器、混淆器和预校验器。 压缩步骤检测并删除未使用的类、字段、方法和...

  • 28、图片压缩

    一、利用JPG的压缩方法(有损压缩) 二、利用PNG的压缩方法(无损压缩)

  • iOS 图片压缩总结

    一.压缩方式和方法 1.压缩方式 1.1 质量压缩1.2 尺寸压缩1.3 质量和尺寸共同压缩 2.压缩方法 2.1...

网友评论

      本文标题:Java压缩方法分析

      本文链接:https://www.haomeiwen.com/subject/vgkqbftx.html