• 2021.05.06 java实现文件压缩和解压


    java作为一门相对比较完善的语言,有着特别丰富的接口和系统类,今天我们来看两个特殊的I/O流,这两个类可以协助我们实现文件的压缩和解压:GZIPOutputStream/GZIPInputStreamZipOutputStream/ZipInputStream,这两对压缩流都位于java.util.zip包下。这两个类,在web开发时也经常会用到,比如文件的批量上传和批量下载,所以掌握这两对流,可以有助于你很多web需求的实现。今天我们就来看下如何用他们来实现文件的压缩和解压。

    GZ压缩

    先上代码:

    /**
         * 压缩gz
         * @param filePath
         * @return
         * @throws Exception
         */
        private static String compressFileByGZ(String filePath) throws Exception {
            File file = new File(filePath);
            System.out.println(file.getName());
            String outputFIleName = file.getName() + ".gz";
            GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(outputFIleName));
    
            FileInputStream fileInputStream = new FileInputStream(filePath);
            byte[] bytes = new byte[1024];
            int read;
            while ((read = fileInputStream.read(bytes)) != -1) {
                gzipOutputStream.write(bytes);
            }
            fileInputStream.close();
            gzipOutputStream.close();
    
            return outputFIleName;
        }
    

    GZ这里演示的只是单个文件的,多文件压缩从GZIP的接口来看,应该是不支持的,至少原生不支持,因为压缩包里面的文件名和GZ压缩包文件名是一致的,所以多文件压缩应该是有问题的,后面我再研究下,今天鉴于时间,就不深入了。压缩后的效果:

    这里选了一张图片,压缩率43%,原文件大小为17kb,压缩后只有9.68kb

    GZ解压

    解压就是把压缩包里面的文件拿出来,相比于zipgz解压后的文件名只能取压缩文件的名字,因为它本身没有保留压缩的文件名。

    /**
         * 解压GZ
         * @param filePath
         * @throws Exception
         */
        public static void extractGz(String filePath) throws Exception {
            FileInputStream fileInputStream = new FileInputStream(filePath);
            GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream);
            FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath).getName().replace(".gz", ""));
            byte[] bytes = new byte[1024];
            int x ;
            while ((x = gzipInputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes);
            }
            fileInputStream.close();
            gzipInputStream.close();
            fileOutputStream.close();
        }
    

    解压后的文件:

    ZIP压缩

    zip的压缩就比较有意思了,原生支持多文件压缩,需要注意的是每个文件要单独创建一个ZipEntry,它就相当于压缩包里面每一个单独的文件,它包含被压缩文件的文件信息,所以解压的时候,可以拿到之前压缩的文件名。

    /**
         * 压缩zip
         *
         * @param filePath
         * @return
         * @throws Exception
         */
        private static String compressFileByZIP(String filePath) throws Exception {
            File file = new File(filePath);
            System.out.println(file.getName());
            String outputFIleName = file.getName() + ".zip";
            ArrayList<File> fileList = new ArrayList<>();
            if (file.isDirectory()) {
                fileList.addAll(Arrays.asList(file.listFiles()));
            } else {
                fileList.add(file);
            }
            FileInputStream fileInputStream = null;
            CheckedOutputStream checkedOutputStream = new CheckedOutputStream(new FileOutputStream(outputFIleName), new Adler32());
            ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream);
            for (File f : fileList) {
                if (f.isDirectory()) {
                    continue;
                }
                zipOutputStream.putNextEntry(new ZipEntry(f.getName()));
                fileInputStream = new FileInputStream(f);
                byte[] bytes = new byte[1024];
                int read;
                while ((read = fileInputStream.read(bytes)) != -1) {
                    zipOutputStream.write(bytes);
                }
            }
            byte[] bytes = new byte[1024];
            int read;
            while ((read = fileInputStream.read(bytes)) != -1) {
                zipOutputStream.write(bytes);
            }
            fileInputStream.close();
            zipOutputStream.close();
    
            return outputFIleName;
        }
    

    zip本身就支持多文件,所以这里就演示了多文件压缩,单个文件也做了兼容。压缩文件效果:

    被压缩文件夹,共212个文件

    文件大小

    压缩文件

    压缩后34.8MB,和我电脑上安装的压缩软件做了对比,压缩后大小是一样的

    ZIP解压

    解压我们前面说了,它的ZipEntry包含被压缩文件的信息,所以就很简单了:

     /**
         * 解压zip文件
         * @param filePath
         * @return
         * @throws Exception
         */
        public static String extractZip(String filePath) throws Exception{
            FileInputStream fileInputStream = new FileInputStream(filePath);
            CheckedInputStream checkedInputStream = new CheckedInputStream(fileInputStream, new Adler32());
            ZipInputStream zipInputStream = new ZipInputStream(checkedInputStream);
            ZipEntry zipEntry;
    
            FileOutputStream fileOutputStream = null;
            File savePath = new File(filePath.replace(".zip", ""));
            if (!savePath.exists()) {
                savePath.mkdir();
            }
            BufferedInputStream bufferedInputStream = new BufferedInputStream(zipInputStream);
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                fileOutputStream = new FileOutputStream(savePath.getName() + "/" + zipEntry.getName());
                int x;
                byte[] bytes = new byte[1024];
                while ((x = bufferedInputStream.read(bytes)) != -1) {
                    fileOutputStream.write(bytes);
                }
                fileOutputStream.close();
            }
            zipInputStream.close();
            fileInputStream.close();
            return null;
        }
    

    第一个循环是从流里面拿出压缩包中的每一个文件(zipEntry),第二个循环就是从流中把被压缩文件还原成压缩前的格式。

    ZIP补充

    这里要补充两点,一个是CheckedInputStream/CheckedOutputStream。这一对流是为各种流提供校验和的,也就是校验输出输入数据的;另一个也和CheckedOutputStream/CheckedInputStream有关,就是构建这两个流的时候传的Adler32在,这里其实表示的是计算和校验文件的校验和的方式(Checksum),取值有两种,分别是Adler32CRC32,但是因为Adler32更快,所以这里我们用了它,CRC32虽然慢,但也更准确。

    总结

    总的来说,java文件压缩和解压方面的内容还是比较简单的,主要涉及了I/O流方面的知识点,各位小伙伴只要掌握了上面两种压缩和解压的方式,大部分web端开发的压缩和解压需求也可以迎刃而解了,当然最重要的一点是,要自己动手做,不然就真的变成了:

    眼睛:我会了……

    手:那你来

    眼睛:……

    好了,大家晚安吧

    项目路径:

    https://github.com/Syske/example-everyday
    

    本项目会每日更新,让我们一起学习,一起进步,遇见更好的自己,加油呀

  • 相关阅读:
    easyui datagrid 悬浮事件
    wpf 遍历控件及其值
    wpf 异常处理和关闭进程
    c# 反射类字段
    wpf 获取datagrid中模板中控件
    JavaScript中ActiveXObject对象
    动画执行完后再次执行
    鼠标滚轮事件(mousewheel 与 DOMMouseScroll)
    移动端的小问题整理
    flex布局兼容问题
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/14747987.html
Copyright © 2020-2023  润新知