java zip简易压缩操作

压缩

基本操作

1.创建一个ZIP输出流,ZIP操作也是基于流的

ZipOutputStream zos = new ZipOutputStream(...);//参数为OutputStream

2.设置一些参数

// 设置压缩方法
zos.setMethod(ZipOutputStream.DEFLATED);
zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
// zos.setLevel(Deflater.BEST_SPEED);
zos.setComment("zip文件说明");

3.写入数据(ZipEntry、目录)

数据的来源可以是任何地方。最终都是以字节形式写入到ZIP流中

要区分ZIP中的文件,可以创建  ZipEntry 

ZipEntry的名称中如果有文件分隔符 / ,那么压缩时也会有相应的目录

比如 a/b/c.jpg  就会产生 目录 a/  目录 a/b/  及a/b/中的文件 c.jpg

ZipEntry entry = new ZipEntry(file.getName());//名称的层级会体现为目录
entry.setMethod(ZipEntry.DEFLATED); // 压缩方法默认为DEFLATED
// entry.setMethod(ZipEntry.STORED); // STORED(不压缩)。当使用STORED压缩方法时,需要设置未压缩的数据大小和CRC-32校验和,否则压缩和解压缩时会出现错误。
entry.setSize(file.length()); // 设置未压缩的数据大小,这里设置的是文件大小
// 计算 CRC-32 校验码
// byte[] data = Files.readAllBytes(file.toPath());
// CRC32 crc = new CRC32();
// crc.update(data);
// entry.setCrc(crc.getValue()); // 设置CRC-32校验和,用于保证压缩后的数据完整性,尽量别手动设置,可以通过CRC-32计算
entry.setCompressedSize(file.length()); // 设置压缩后的数据大小,这里设置的是使用DEFLATED方法压缩后的数据大小
entry.setExtra(new byte[]{}); // 设置额外的数据,这里设置为空
entry.setComment("file comment"); // 设置ZipEntry的注释,即文件说明
entry.setCreationTime(FileTime.from(Instant.now())); // 设置文件的创建时间
entry.setLastAccessTime(FileTime.from(Instant.now())); // 设置文件的最后访问时间
entry.setLastModifiedTime(FileTime.from(Instant.now())); // 设置文件的最后修改时间。

将ZipEntry添加到ZIP流中,并将写入指针定位到该ZipEntry起点

zos.putNextEntry(entry);

向ZIP流写入数据,这时写入的数据会绑定在当前ZipEntry中。

zos.write(...)

结束当前ZipEntry的写入,准备写下一个ZipEntry

zos.closeEntry();

4.结束关闭输出流

zos.close()

案例代码

压缩文件到http输出,压缩网络资源到http输出

package com.ctc.hikvision_capture_service.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RequestMapping("/test")
@RestController
@CrossOrigin
public class TestController {

    /**
     * 将文件夹压缩到http响应流里面去,这个文件夹里面不能有文件夹
     * @param response
     */
    @GetMapping("/dzip")
    public void dzip(HttpServletResponse response){
        try {
            String filename = new String("地方.zip".getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1);
            response.addHeader("Content-Disposition","attachment; filename=\"" + filename + "\"");
            ServletOutputStream outputStream = response.getOutputStream();
            zipCompressStream(new File("E:\\test_video"),outputStream);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将一系列网络资源压缩到http输出流里面去,这些网络资源是可以直接通过URL获取的那种
     * @param response
     */
    @GetMapping("/dzipu")
    public void dzipu(HttpServletResponse response){
        try {
            String filename = new String("地方.zip".getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1);
            response.addHeader("Content-Disposition","attachment; filename=\"" + filename + "\"");
            ServletOutputStream outputStream = response.getOutputStream();
            List<String> urlList = Arrays.asList("https://www.bejson.com/static/bejson/img/logo.png",
                    "https://s0.2mdn.net/simgad/4596400126827373795",
                    "https://csdnimg.cn/release/blogv2/dist/pc/img/npsFeel5.png");
            zipCompressURLS(urlList,outputStream);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 压缩为本地文件,然后再读出,完全缓存到内存中,再写入到http输出流(反面案例)
     * @param response
     */
    @GetMapping("/dzip22")
    public void dzip22(HttpServletResponse response){
        try {
            ServletOutputStream outputStream = response.getOutputStream();
            File zipFile = new File("E:\\test_video.zip");
            zipCompress(new File("E:\\test_video"), zipFile);
            FileInputStream fileInputStream = new FileInputStream(zipFile);
            ByteArrayOutputStream b = new ByteArrayOutputStream();
            int x = 0;
            while ((x = fileInputStream.read()) != -1){
                b.write(x);
            }
            byte[] byteArray = b.toByteArray();
            outputStream.write(byteArray);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     *
     * @param urls 一些网络资源文件
     * @param outputStream 输出流
     */
    public static void zipCompressURLS(Collection<String> urls, OutputStream outputStream) {
        try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
            // 设置压缩方法
            zos.setMethod(ZipOutputStream.DEFLATED);
            zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
            // zos.setLevel(Deflater.BEST_SPEED);
            zos.setComment("zip文件说明");
            // 处理文件夹
            int i = 0;
            for (String u : urls) {
                String[] split = u.split("\\.");
                String suffix = split[split.length - 1];
                addZipURL(u,zos,"file_"+ i++ +"."+suffix);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void zipCompressStream(File sourceFile, OutputStream outputStream) {
        try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
            // 设置压缩方法
            zos.setMethod(ZipOutputStream.DEFLATED);
            zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
            // zos.setLevel(Deflater.BEST_SPEED);
            zos.setComment("zip文件说明");
            // 处理文件夹
            if (sourceFile.exists() && sourceFile.isDirectory() && Objects.nonNull(sourceFile.listFiles())){
                Arrays.stream(Objects.requireNonNull(sourceFile.listFiles())).forEach(file -> {
                    addZipFile(file, zos);
                });
            }else{
                addZipFile(sourceFile, zos);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 压缩文件(支持单个文件和单个文件夹)
     * @param sourceFile 被压缩文件/文件夹
     * @param zipFile Zip文件
     */
    public static void zipCompress(File sourceFile, File zipFile) {
        try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
            // 设置压缩方法
            zos.setMethod(ZipOutputStream.DEFLATED);
            zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
            // zos.setLevel(Deflater.BEST_SPEED);
            zos.setComment("zip文件说明");
            // 处理文件夹
            if (sourceFile.exists() && sourceFile.isDirectory() && Objects.nonNull(sourceFile.listFiles())){
                Arrays.stream(Objects.requireNonNull(sourceFile.listFiles())).forEach(file -> {
                    addZipFile(file, zos);
                });
            }else{
                addZipFile(sourceFile, zos);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向ZIP中添加文件
     * @param file 源文件
     * @param zos zip输出流
     */
    private static void addZipFile(File file, ZipOutputStream zos){
        if (!file.exists() || file.isDirectory()){
            throw new RuntimeException("文件不存在或该文件为文件夹,请检查");
        }
        try {
            // 读入文件
            FileInputStream fis = new FileInputStream(file);
            // 创建压缩对象并设置一些属性
            ZipEntry entry = new ZipEntry(file.getName());
            entry.setMethod(ZipEntry.DEFLATED); // 压缩方法默认为DEFLATED
            // entry.setMethod(ZipEntry.STORED); // STORED(不压缩)。当使用STORED压缩方法时,需要设置未压缩的数据大小和CRC-32校验和,否则压缩和解压缩时会出现错误。
            entry.setSize(file.length()); // 设置未压缩的数据大小,这里设置的是文件大小
            // 计算 CRC-32 校验码
            // byte[] data = Files.readAllBytes(file.toPath());
            // CRC32 crc = new CRC32();
            // crc.update(data);
            // entry.setCrc(crc.getValue()); // 设置CRC-32校验和,用于保证压缩后的数据完整性,尽量别手动设置,可以通过CRC-32计算
            entry.setCompressedSize(file.length()); // 设置压缩后的数据大小,这里设置的是使用DEFLATED方法压缩后的数据大小
            entry.setExtra(new byte[]{}); // 设置额外的数据,这里设置为空
            entry.setComment("file comment"); // 设置ZipEntry的注释,即文件说明
            entry.setCreationTime(FileTime.from(Instant.now())); // 设置文件的创建时间
            entry.setLastAccessTime(FileTime.from(Instant.now())); // 设置文件的最后访问时间
            entry.setLastModifiedTime(FileTime.from(Instant.now())); // 设置文件的最后修改时间。
            // 向ZIP输出流中添加一个ZIP实体,构造方法中的name参数指定文件在ZIP包中的文件名
            zos.putNextEntry(entry);
            // 向ZIP实体中写入内容
            byte[] buf = new byte[1024];
            int len;
            while ((len = fis.read(buf)) > 0) {
                zos.write(buf, 0, len);
            }
            // 关闭ZipEntry
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 下载一个URL的数据直接放入输出流中
     * @param url
     * @param zos
     * @param name
     */
    private static void addZipURL(String url, ZipOutputStream zos, String name){
        try {
            URL urlSource = new URL(url);
            InputStream inputStream = urlSource.openStream();
            addZipStream(inputStream,zos,name);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(url + " download failed");
//            throw new RuntimeException(e);
        }
    }

    /**
     * 向ZIP中添加Stream
     * @param zos zip输出流
     */
    private static void addZipStream(InputStream inputStream, ZipOutputStream zos, String name){

        try {
            // 创建压缩对象并设置一些属性
            ZipEntry entry = new ZipEntry(name);
            entry.setMethod(ZipEntry.DEFLATED); // 压缩方法默认为DEFLATED
            // entry.setMethod(ZipEntry.STORED); // STORED(不压缩)。当使用STORED压缩方法时,需要设置未压缩的数据大小和CRC-32校验和,否则压缩和解压缩时会出现错误。
//            entry.setSize(file.length()); // 设置未压缩的数据大小,这里设置的是文件大小
            // 计算 CRC-32 校验码
            // byte[] data = Files.readAllBytes(file.toPath());
            // CRC32 crc = new CRC32();
            // crc.update(data);
            // entry.setCrc(crc.getValue()); // 设置CRC-32校验和,用于保证压缩后的数据完整性,尽量别手动设置,可以通过CRC-32计算
//            entry.setCompressedSize(file.length()); // 设置压缩后的数据大小,这里设置的是使用DEFLATED方法压缩后的数据大小
            entry.setExtra(new byte[]{}); // 设置额外的数据,这里设置为空
            entry.setComment("file comment"); // 设置ZipEntry的注释,即文件说明
            entry.setCreationTime(FileTime.from(Instant.now())); // 设置文件的创建时间
            entry.setLastAccessTime(FileTime.from(Instant.now())); // 设置文件的最后访问时间
            entry.setLastModifiedTime(FileTime.from(Instant.now())); // 设置文件的最后修改时间。
            // 向ZIP输出流中添加一个ZIP实体,构造方法中的name参数指定文件在ZIP包中的文件名
            zos.putNextEntry(entry);
            // 向ZIP实体中写入内容
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                zos.write(buf, 0, len);
            }
            // 关闭ZipEntry
            zos.closeEntry();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

含有子目录的递归压缩

子目录的压缩根本是靠ZipEntry的文件名,文件名的层级会体现到最终的ZIP压缩包中,

如果想要保留顶层文件夹,basePath稍作改动即可。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class FileZipTest {

    public static void main(String[] args) {
        zipCompress(new File("E:/test_img"), new File("E:/a.zip"));
    }

    /**
     * 压缩文件(支持单个文件和单个文件夹)
     * @param sourceFile 被压缩文件/文件夹
     * @param zipFile Zip文件
     */
    public static void zipCompress(File sourceFile, File zipFile) {
        try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
            // 设置压缩方法
            zos.setMethod(ZipOutputStream.DEFLATED);
            zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
            // zos.setLevel(Deflater.BEST_SPEED);
            zos.setComment("zip文件说明");
            // 处理文件夹
            if (sourceFile.exists() && sourceFile.isDirectory() && Objects.nonNull(sourceFile.listFiles())){
                Arrays.stream(Objects.requireNonNull(sourceFile.listFiles())).forEach(file -> {
                    addZipFile(file, zos, "");
                });
            }else{
                addZipFile(sourceFile, zos, "");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向ZIP中添加文件
     * @param file 源文件
     * @param zos zip输出流
     */
    private static void addZipFile(File file, ZipOutputStream zos, String basePath){
        if (!file.exists()){
            throw new RuntimeException("文件不存在,请检查");
        }
        String path = "".equals(basePath) ? "" : basePath + "/";
        if (file.isDirectory()){
            File[] files = file.listFiles();
            assert files != null;
            for (File file1 : files) {

                addZipFile(file1, zos, path + file.getName());
            }
            return;
        }
        try {
            // 读入文件
            FileInputStream fis = new FileInputStream(file);
            // 创建压缩对象并设置一些属性
            ZipEntry entry = new ZipEntry(path + file.getName());
            entry.setMethod(ZipEntry.DEFLATED); // 压缩方法默认为DEFLATED
            // entry.setMethod(ZipEntry.STORED); // STORED(不压缩)。当使用STORED压缩方法时,需要设置未压缩的数据大小和CRC-32校验和,否则压缩和解压缩时会出现错误。
            entry.setSize(file.length()); // 设置未压缩的数据大小,这里设置的是文件大小
            // 计算 CRC-32 校验码
            // byte[] data = Files.readAllBytes(file.toPath());
            // CRC32 crc = new CRC32();
            // crc.update(data);
            // entry.setCrc(crc.getValue()); // 设置CRC-32校验和,用于保证压缩后的数据完整性,尽量别手动设置,可以通过CRC-32计算
            entry.setCompressedSize(file.length()); // 设置压缩后的数据大小,这里设置的是使用DEFLATED方法压缩后的数据大小
            entry.setExtra(new byte[]{}); // 设置额外的数据,这里设置为空
            entry.setComment("file comment"); // 设置ZipEntry的注释,即文件说明
            entry.setCreationTime(FileTime.from(Instant.now())); // 设置文件的创建时间
            entry.setLastAccessTime(FileTime.from(Instant.now())); // 设置文件的最后访问时间
            entry.setLastModifiedTime(FileTime.from(Instant.now())); // 设置文件的最后修改时间。
            // 向ZIP输出流中添加一个ZIP实体,构造方法中的name参数指定文件在ZIP包中的文件名
            zos.putNextEntry(entry);
            // 向ZIP实体中写入内容
            byte[] buf = new byte[1024];
            int len;
            while ((len = fis.read(buf)) > 0) {
                zos.write(buf, 0, len);
            }
            // 关闭ZipEntry
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值