美文网首页
详解java操作zip文件

详解java操作zip文件

作者: 平凡的柚子 | 来源:发表于2021-01-04 16:51 被阅读0次

    简介

    平时我们都是使用WinZip,2345好压等软件来操作zip文件,java也提供了ZipOutputStream,ZipEntry等API创建和解析zip文件。

    压缩

    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.util.Objects;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;
    
    public class Client {
    
      public static void main(String[] args) {
        compressFileToZip("D:\\original_compute\\sku-20140802",
            "D:\\original_compute\\sku-20140802.zip");
      }
    
      /**
       * 读取文件内容并压缩,既支持文件也支持文件夹
       *
       * @param filePath 文件路径
       */
      private static void compressFileToZip(String filePath,
          String zipFilePath) {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
          //递归的压缩文件夹和文件
          doCompress("", filePath, zos);
          //必须
          zos.finish();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
      private static void doCompress(String parentFilePath, String filePath, ZipOutputStream zos) {
        File sourceFile = new File(filePath);
        if (!sourceFile.exists()) {
          return;
        }
        String zipEntryName = parentFilePath + "/" + sourceFile.getName();
        if (parentFilePath.isEmpty()) {
          zipEntryName = sourceFile.getName();
        }
        if (sourceFile.isDirectory()) {
          File[] childFiles = sourceFile.listFiles();
          if (Objects.isNull(childFiles)) {
            return;
          }
          for (File childFile : childFiles) {
            doCompress(zipEntryName, childFile.getAbsolutePath(), zos);
          }
        } else {
          int len = -1;
          byte[] buf = new byte[1024];
          try (InputStream input = new BufferedInputStream(new FileInputStream(sourceFile))) {
            zos.putNextEntry(new ZipEntry(zipEntryName));
            while ((len = input.read(buf)) != -1) {
              zos.write(buf, 0, len);
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }
    

    生成的压缩文件为


    每一个ZipEntry表示一个压缩子文件,如sku.html。注意,ZipEntry的name必须为目录名+文件名,如sku-20140802/sku/sku.html。

    /**
     * This class implements an output stream filter for writing files in the
     * ZIP file format. Includes support for both compressed and uncompressed
     * entries.
     *
     * @author      David Connelly
     * @since 1.1
     */
    public
    class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
    
        /**
         * 在写入文件内容之前写入一些zip格式相关的数据
         */
        public void putNextEntry(ZipEntry e) throws IOException {
            ensureOpen();
            if (current != null) {
                closeEntry();       // close previous entry
            }
            if (e.xdostime == -1) {
                // by default, do NOT use extended timestamps in extra
                // data, for now.
                e.setTime(System.currentTimeMillis());
            }
            if (e.method == -1) {
                e.method = method;  // use default method
            }
            // store size, compressed size, and crc-32 in LOC header
            e.flag = 0;
            switch (e.method) {
            case DEFLATED:
                // store size, compressed size, and crc-32 in data descriptor
                // immediately following the compressed entry data
                if (e.size  == -1 || e.csize == -1 || e.crc   == -1)
                    e.flag = 8;
    
                break;
            case STORED:
                // compressed size, uncompressed size, and crc-32 must all be
                // set for entries using STORED compression method
                if (e.size == -1) {
                    e.size = e.csize;
                } else if (e.csize == -1) {
                    e.csize = e.size;
                } else if (e.size != e.csize) {
                    throw new ZipException(
                        "STORED entry where compressed != uncompressed size");
                }
                if (e.size == -1 || e.crc == -1) {
                    throw new ZipException(
                        "STORED entry missing size, compressed size, or crc-32");
                }
                break;
            default:
                throw new ZipException("unsupported compression method");
            }
            if (! names.add(e.name)) {
                throw new ZipException("duplicate entry: " + e.name);
            }
            if (zc.isUTF8())
                e.flag |= USE_UTF8;
            current = new XEntry(e, written);
            xentries.add(current);
            writeLOC(current);
        }
    
        /**
         * 文件内容写入
         */
        public synchronized void write(byte[] b, int off, int len)
            throws IOException
        {
            ensureOpen();
            if (off < 0 || len < 0 || off > b.length - len) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return;
            }
    
            if (current == null) {
                throw new ZipException("no current ZIP entry");
            }
            ZipEntry entry = current.entry;
            switch (entry.method) {
            case DEFLATED:
                super.write(b, off, len);
                break;
            case STORED:
                written += len;
                if (written - locoff > entry.size) {
                    throw new ZipException(
                        "attempt to write past end of STORED entry");
                }
                out.write(b, off, len);
                break;
            default:
                throw new ZipException("invalid compression method");
            }
            crc.update(b, off, len);
        }
    
        /**
         * 文件内容写入之后写入zip格式相关的数据
         */
        public void finish() throws IOException {
            ensureOpen();
            if (finished) {
                return;
            }
            if (current != null) {
                closeEntry();
            }
            // write central directory
            long off = written;
            for (XEntry xentry : xentries)
                writeCEN(xentry);
            writeEND(off, written - off);
            finished = true;
        }
    }
    

    可以看到,ZipOutputStream也是扩展DeflaterOutputStream.

    解压

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipFile;
    import java.util.zip.ZipInputStream;
    
    public class Client {
    
      public static void main(String[] args) throws Exception {
        decompressFromZip("D:/original_compute/sku-20140802.zip",
            "D:/original_compute/testzip/");
      }
    
      /**
       * 文件解压缩,支持文件和文件夹的解压
       *
       * @param zipFilePath 压缩包路径
       * @param destFilePath 解压路径
       */
      private static void decompressFromZip(String zipFilePath, String destFilePath) {
        File file = new File(zipFilePath);
        try (ZipFile zipFile = new ZipFile(file);
            ZipInputStream zis = new ZipInputStream(new FileInputStream(file))) {
          ZipEntry zipEntry = null;
          while ((zipEntry = zis.getNextEntry()) != null) {
            String fileName = destFilePath + "/" + zipEntry.getName();
            File entryFile = new File(fileName);
            if (zipEntry.isDirectory()) {
              //创建文件夹
              entryFile.mkdir();
            } else {
              //创建文件之前必须保证父文件夹存在
              if (!entryFile.getParentFile().exists()) {
                entryFile.getParentFile().mkdirs();
              }
              //创建文件
              entryFile.createNewFile();
            }
            try (InputStream input = zipFile.getInputStream(zipEntry);
                OutputStream output = new FileOutputStream(entryFile)) {
              int len = -1;
              byte[] buf = new byte[1024];
              while ((len = input.read(buf)) != -1) {
                output.write(buf, 0, len);
              }
            }
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
    
      }
    }
    

    解压主要就是要获取到所有的压缩子文件,就是ZipEntry,将每一个ZipEntry重新生成文件或文件夹,生成文件时要确保父文件夹已经存在。



    最新2020整理收集的一些高频面试题(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、jvm、源码、算法等详细讲解,也有详细的学习规划图,面试题整理等,需要获取这些内容的朋友请加Q君样:11604713672

    相关文章

      网友评论

          本文标题:详解java操作zip文件

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