您当前的位置: 首页 >  Java

Charge8

暂无认证

  • 4浏览

    0关注

    447博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java 压缩与解压zip文件

Charge8 发布时间:2018-10-30 21:17:13 ,浏览量:4

一、压缩文件大致可以分为三种:ZIP、JAR、GZ。

压缩流

      在日常中经常会使用到像WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行压缩以方便传输。

     在JAVA中,为了减少传输时的数据量也提供了专门的压缩流,可以将文件或文件夹压缩成 ZIP、JAR、GZIP等文件的格式。  

压缩流的实现:正常情况下在IO操作中,所有的类库都是在io包中。

在JAVA IO中,不仅可以实现ZIP压缩格式的输入、输出,也可以实现ZIP、JAR及GZIP文件格式的压缩:

JAR压缩的支持类保存在java.util.jar包中,常用的类有如下几个:      JAR压缩输出流:JarOutputStream      JAR压缩输入流:JarInputStream      JAR文件:JARFile      JAR实体:JAREntry

GZIP是用于UNIX系统的文件压缩,在Linux中经常会使用到*.gz的文件,就是GZIP格式,GZIP压缩的支持类保存在java.util.zip包中,常用的类有如下几个:      GZIP压缩输出流:GZIPOutputStream      GZIP压缩输入流:GZIPInputStream  

ZIP是一种较为常见的压缩形式,在Java中要想实现ZIP的压缩需要导入java.util.zip包,可以使用此包中的ZipFile、ZipOutputStream、ZipInputStream、ZipEntry几个类完成。

 

1、ZipOutputStream类

        ZipOutputStream是OutputStream的子类,该类实现了以ZIP文件格式写入文件的输出流过滤器。 包括对压缩和未压缩条目的支持。

    • voidputNextEntry(ZipEntry e)

      开始编写新的ZIP文件条目,并将流定位到条目数据的开头。

      voidsetComment(String comment)

      设置ZIP文件注释。

2、ZipInputStream类

        ZipInputStream是InputStream的子类,该类实现了以ZIP文件格式读取文件的输入流过滤器。 包括对压缩和未压缩条目的支持。

    • protected ZipEntrycreateZipEntry(String name)

      为指定的条目名称创建一个新的 ZipEntry对象。

      ZipEntrygetNextEntry()

      读取下一个ZIP文件条目,并将流定位在条目数据的开头。如果没有更多条目,则为null 

3、ZipFile类:此类用于从zip文件读取条目。

        在Java中,ZipFile是一个专门表示zip压缩文件(.zip)的类,每一个压缩文件都可以使用 ZipFile表示,还可以使用 ZipFile根据压缩后的文件名找到每一个压缩文件中的ZipEntry对象并将其进行解压缩操作。

        ZipFile在实例化的时候必须接收File类的实例,此File类的实例是指向一个压缩的*.zip文件。

    • ZipFile(File file)

      打开一个ZIP文件,读取指定的File对象。

      ZipFile(String name)

      打开一个zip文件进行阅读。

    • voidclose()

      关闭ZIP文件。

      StringgetComment()

      返回zip文件注释,否则返回null。

      ZipEntrygetEntry(String name)

      返回指定名称的zip文件条目,如果找不到则返回null。

      InputStreamgetInputStream(ZipEntry entry)

      返回用于读取指定zip文件条目内容的输入流。

      StringgetName()

      返回ZIP文件的路径名。

4、ZipEntry类:此类用于表示ZIP文件条目。

        在Java中,每一个压缩文件(.zip)中都会存在多个子文件,那么每一个子文件使用ZipEntry对象表示。可以获取到文件条目的数据大小,条目名称等文件条目信息

        ZipEntry在实例化的时候必须要设置名称,此名称实际上就是压缩文件中的每一个文件条目的名称。

    • ZipEntry(String name)

      创建具有指定名称的新的zip条目。

    • StringgetComment()

      返回条目的注释字符串。

      longgetCrc()

      返回未压缩条目数据的CRC-32校验和。

      StringgetName()

      返回条目的名称。

      longgetSize()

      返回条目数据的未压缩大小。

      longgetTime()

      返回条目的最后修改时间。

      voidsetTime(long time)

      设置条目的最后修改时间。

二、自定义ZipUtil工具类

包含三个方法:

    1、压缩一个文件

    2、压缩一个文件夹(嵌套或不嵌套都可以)

       1)递归实现嵌套文件或不嵌套文件夹的压缩 

        对一个文件夹进行压缩,例如,现在在某盘存在一个a文件夹。从使用各种压缩软件的经验来看,如果现在要进行压缩的话,则在压缩之后的文件中应该存在一个a文件夹。在文件夹中应该存放着各个压缩文件。所以在实现的时候就应该列出文件夹中的全部内容,并把每一个内容设置成ZipEntry的对象,保存到压缩文件之中。    

 

    3、解压zip文件(里面嵌套或不嵌套都可以)到指定目录下

直接上代码


import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtil {
    private ZipUtil(){}
    /**
     * 压缩一个文件
     *
     * @param file    要压缩的文件
     * @param zipFile 压缩后的zip文件
     * @return boolean  true-压缩成功,false-压缩失败
     */
    public static boolean zipOneFile(File file, File zipFile) {
        try (
                InputStream input = new FileInputStream(file);
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
        ) {
            // 压缩读写之前必须通过putNextEntry设置一个ZipEntry对象(表示ZIP文件条目)
            zipOut.putNextEntry(new ZipEntry(file.getName()));
            //zipOut.setComment("UTF-8"); // 设置ZIP文件注释
            byte[] buffer = new byte[2048];
            int len = -1;
            while ((len = input.read(buffer)) != -1) {
                zipOut.write(buffer, 0, len);
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 压缩一个文件夹(嵌套或不嵌套都可以)
     *
     * @param fileDir 要压缩的文件夹
     * @param zipFile 压缩后的zip文件
     * @return boolean  true-压缩成功,false-压缩失败
     */
    public static boolean zipFileDir(File fileDir, File zipFile) {
        // 检查目录是否存在,不存在时创建
        if (!fileDir.isDirectory()) {
            fileDir.mkdirs();
        }
        try (
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
        ) {
            File[] files = fileDir.listFiles();
            for (File fileSrc : files) {
                recursionZip(fileSrc, zipOut, fileDir.getName());
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 递归实现文件或文件夹的压缩
     *
     * @param file     要压缩的文件或目录
     * @param zipOut   压缩后的zip文件输出流
     * @param filePath 要压缩的文件路径或目录路径(最后不带/)
     * @throws Exception
     */
    private static void recursionZip(File file, ZipOutputStream zipOut, String filePath) throws Exception {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File fileSrc : files) {
                recursionZip(fileSrc, zipOut, filePath + File.separator + file.getName());
            }
        } else {
            InputStream input = new FileInputStream(file);
            zipOut.putNextEntry(new ZipEntry(filePath + File.separator + file.getName()));
            byte[] buffer = new byte[2048];
            int len = -1;
            while ((len = input.read(buffer)) != -1) {
                zipOut.write(buffer, 0, len);
            }
            input.close();
        }
    }

    /**
     * 解压zip文件(里面嵌套或不嵌套都可以)到指目录下
     *
     * @param file:需要解压的zip文件
     * @param destDir:将zip文件解压到某个路径下(最后不带/)
     * @throws Exception
     */
    public static void unZipFile(File file, String destDir) throws Exception {
        ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file)); // 实例化压缩输入流
        ZipFile zipFile = new ZipFile(file);  // 实例化ZipFile对象
        ZipEntry zipEntry = null;
        File outFile = null;
        OutputStream out = null;
        InputStream input = null;
        try {
            while ((zipEntry = zipInput.getNextEntry()) != null) {
                //System.out.println("解压文件: " + zipEntry.getName()); // 解压文件: file01\1.png
                outFile = new File(destDir + File.separator + zipEntry.getName());

                if(zipEntry.isDirectory()){
                    outFile.delete();
                    outFile.mkdirs();
                    continue;
                }
                if (outFile.exists()) {
                    outFile.delete();
                }else{
                    outFile.createNewFile();
                }

                input = zipFile.getInputStream(zipEntry); // 得到每一个压缩实体对象的输入流
                out = new FileOutputStream(outFile); // 实例化文件输出流
                byte[] buffer = new byte[2048];
                int len = -1;
                while ((len = input.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
            }
        } finally {
            if (zipInput != null) zipInput.close();
            if (out != null) out.close();
            if (input != null) input.close();
            if (zipFile != null) zipFile.close();
        }
    }


    public static void main(String[] args) {
//        File file = new File("E:/java/text.txt");
//        File zipFile = new File("E:/java/text.zip");
//        boolean flag = ZipUtil.zipOneFile(file, zipFile);
//        System.out.println(flag);

//        File fileDir = new File("E:/java/file01");
//        File zipFile = new File("E:/java/file01.zip");
//        boolean flag = ZipUtil.zipFileDir(fileDir,zipFile);
//        System.out.println(flag);

        File zipFile = new File("E:/java/file01.zip");
        try {
            ZipUtil.unZipFile(zipFile, "E:/java/unzip");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

     本人亲测OK,但是解压只能是xx.zip文件下只能是一个文件夹条目,它里面嵌套包含ok,

      

有时我们可能拿到的是文件的 二进制数据,通过二进制流包装一一下,就可以了。比如:

    @PostMapping("/upload")
    @ResponseBody
    public String upload(MultipartFile file) {
        try (
                ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));
        ) {
            ZipEntry zipEntry = null;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.isDirectory()) {
                    System.out.println("==目录==" + zipEntry.getName());
                } else {
                    System.out.println("==文件==" + zipEntry.getName());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "error";
        }
        return "success";
    }

    @GetMapping("/download")
    public ResponseEntity download() {
        List bytesFileItemList = getBytesFileItemList();

        try (
                ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
                ZipOutputStream zipOut = new ZipOutputStream(byteArrayOut);
        ) {
            ZipEntry zipEntry = null;
            for (BytesFileItem fileItem : bytesFileItemList) {
                zipEntry = new ZipEntry(fileItem.getName());
                zipEntry.setSize(fileItem.getContent().length);

                zipOut.putNextEntry(zipEntry);
                zipOut.write(fileItem.getContent());
            }
            zipOut.close();

            String downloadFilenName = "下载嵌套zip文件.zip";
            HttpHeaders headers = new HttpHeaders();
            String downloadFileName = new String(downloadFilenName.getBytes("UTF-8"), "iso-8859-1");
            headers.setContentDispositionFormData("attachment", downloadFileName);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            return new ResponseEntity(byteArrayOut.toByteArray(), headers, HttpStatus.CREATED);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return  ResponseEntity.ok(new byte[0]);
    }

    //模拟下载嵌套文件
    public List getBytesFileItemList() {
        List list = new ArrayList();

        for (int i = 1; i             
关注
打赏
1664721914
查看更多评论
0.0429s