前言

  1. Java实现Zip压缩解压可以使用JDK的原生类java.util.zip,但是JDK 7 之前存在中文文件名乱码问题。

  2. 使用 ant.jar 的org.apache.tools.zip包,可以避免乱码问题。

  3. 使用专门的压缩解压第三方组件,如zip4j,zt-zip等,这种实现方式当然更强大,不过一般场景压缩解压就可以满足需求了。

本博客简单介绍java8下的zip压缩解压。

起步

  • java8

开始

java的io包下运用了装饰模式,对结构不清晰的小伙伴可以先看下装饰模式,在尝试下看java的io包下的源码,来熟悉io操作。

大致设计思想:

装饰成InputStream/OutputStream 装饰成BufferedStream
File FileInputStream(new File) BufferedInputStream(new FileInputStream)
FileOutputStream(new File) BufferedOutputStream(new FileOutputStream)
Writer/Reader BufferedReader/BufferedWriter
FileReader(new File) BufferedReader(new FileReader)
FileWriter(new File) BufferedWriter(new FileWriter)

熟悉之后,让我们开始使用ZipInputStream和ZipOutputStream吧。

这里我们采用 策略模式 设计demo。

  • demo地址

喜欢直接看项目的可以直接 >> demo-zip

  • 代码目录结构

  • 抽象压缩策略类
  1. /**
  2. * @author quaint
  3. * @date 15 February 2020
  4. * @since master
  5. */
  6. public interface CompressionStrategy <T> {
  7. /**
  8. * 是否支持
  9. * @param fileName 文件名称
  10. * @return true
  11. */
  12. boolean support(String fileName);
  13. /**
  14. * 提取策略
  15. * @param inputStream 文件
  16. * @return 数据
  17. * @throws IOException io
  18. */
  19. List<T> extract(InputStream inputStream) throws IOException;
  20. /**
  21. * 压缩策略
  22. * @param dataList 数据
  23. * @param os 输出流
  24. * @throws IOException io
  25. */
  26. void compression(List<T> dataList, OutputStream os) throws IOException;
  27. }
  • zip策略实现
  1. /**
  2. * @author quaint
  3. * @date 15 February 2020
  4. * @since master
  5. */
  6. @Component
  7. public class ZipImageStrategy implements CompressionStrategy<ImageDto> {
  8. /**
  9. * 传入文件类型
  10. */
  11. private static final String ZIP_FORMAT = ".zip";
  12. /**
  13. * 目标类型
  14. */
  15. private static final List<String> TARGET_TYPE = Arrays.asList(".png", ".jpeg", ".jpg", ".gif");
  16. @Override
  17. public boolean support(String fileName) {
  18. if (StringUtils.isEmpty(fileName)) {
  19. return false;
  20. }
  21. return fileName.endsWith(ZIP_FORMAT);
  22. }
  23. @Override
  24. public List<ImageDto> extract(InputStream inputStream) throws IOException {
  25. if (inputStream == null){
  26. return null;
  27. }
  28. // 定义储存数据的list
  29. List<ImageDto> dataList = new ArrayList<>();
  30. // 把输入流 包装为 压缩流
  31. ZipInputStream zis = new ZipInputStream(inputStream);
  32. ZipEntry ze;
  33. while ((ze = zis.getNextEntry()) != null) {
  34. String name = ze.getName();
  35. // 过滤掉 多余的文件/不是图片的文件
  36. if (ze.isDirectory() || name == null || name.contains("__MACOSX") || name.contains(".DS_Store")
  37. || !TARGET_TYPE.contains(name.substring(name.lastIndexOf('.')))) {
  38. continue;
  39. }
  40. // 添加图片到集合
  41. ImageDto imageDto = new ImageDto();
  42. imageDto.setFileName(name.substring(name.lastIndexOf(File.separator) + 1));
  43. // 将文件转换为 byte 数组
  44. ByteArrayOutputStream output = new ByteArrayOutputStream();
  45. byte[] buffer = new byte[1024];
  46. int n;
  47. while(-1 != (n = zis.read(buffer))) {
  48. output.write(buffer, 0, n);
  49. }
  50. imageDto.setBytes(output.toByteArray());
  51. dataList.add(imageDto);
  52. }
  53. zis.close();
  54. return dataList;
  55. }
  56. @Override
  57. public void compression(List<ImageDto> dataList, OutputStream os) throws IOException {
  58. if (CollectionUtils.isEmpty(dataList) || os == null){
  59. return;
  60. }
  61. // 把输出流包装为 压缩流
  62. ZipOutputStream zos = new ZipOutputStream(os);
  63. // 循环写压缩文件
  64. for (ImageDto file : dataList) {
  65. ZipEntry ze = new ZipEntry(file.getFileName());
  66. zos.putNextEntry(ze);
  67. zos.write(file.getBytes(),0,file.getBytes().length);
  68. zos.closeEntry();
  69. }
  70. zos.close();
  71. }
  72. }
  • 图片dto
  1. /**
  2. * 图片实体类,简单版
  3. * @author quaint
  4. * @date 15 February 2020
  5. * @since master
  6. */
  7. @Data
  8. public class ImageDto {
  9. /**
  10. * 文件名称
  11. */
  12. private String fileName;
  13. /**
  14. * 文件字节码
  15. */
  16. private byte[] bytes;
  17. }
  • spi接口
  1. /**
  2. * @author quaint
  3. * @date 11 February 2020
  4. * @since master
  5. */
  6. @RestController
  7. @Slf4j
  8. @Api(tags = {"zip测试demo","分类: 测试"})
  9. public class ZipDemoSpi {
  10. /**
  11. * 单例 包含的对象也是单例, 方便测试, 先把解压的图片 暂时存在这里, 然后在压缩 提供web下载
  12. * swagger 操作流程, -->先解压, -->在压缩
  13. */
  14. private List<ImageDto> tempData;
  15. @Autowired
  16. List<CompressionStrategy<ImageDto>> compressionStrategies;
  17. /**
  18. * 解压web传来的zip
  19. */
  20. @ApiOperation("解压web传来的zip")
  21. @PostMapping("/web/unzip")
  22. public String webUnzipDemo(@RequestParam("fileData") MultipartFile file){
  23. // 选取解压策略
  24. Optional<CompressionStrategy<ImageDto>> best = compressionStrategies.stream()
  25. .filter(strategy -> strategy.support(file.getOriginalFilename())).findFirst();
  26. // 如果支持该类型
  27. if (best.isPresent()){
  28. try {
  29. List<ImageDto> extract = best.get().extract(file.getInputStream());
  30. // 测试解压结果
  31. extract.forEach(imageDto -> log.info("解压到一个图片-->"+imageDto.getFileName()));
  32. tempData = new ArrayList<>();
  33. tempData.addAll(extract);
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. } else {
  38. return "解压失败";
  39. }
  40. return "解压成功";
  41. }
  42. /**
  43. * 解压local传来的zip
  44. */
  45. @ApiOperation("解压local传来的zip")
  46. @PostMapping("/local/unzip")
  47. public String localUnzipDemo(){
  48. // 获取当前项目文件夹的的zip文件
  49. String filePath = System.getProperty("user.dir")+"/demo-zip/src/main/resources/image.zip";
  50. String fileName = filePath.substring(filePath.lastIndexOf('/')+1);
  51. Optional<CompressionStrategy<ImageDto>> best = compressionStrategies.stream()
  52. .filter(strategy -> strategy.support(fileName)).findFirst();
  53. if (best.isPresent()){
  54. try {
  55. InputStream inputStream = new FileInputStream(filePath);
  56. List<ImageDto> extract = best.get().extract(inputStream);
  57. // 测试解压结果
  58. extract.forEach(imageDto -> log.info("解压到一个图片-->"+imageDto.getFileName()));
  59. tempData = new ArrayList<>();
  60. tempData.addAll(extract);
  61. } catch (IOException e) {
  62. e.printStackTrace();
  63. return "本地文件解压异常";
  64. }
  65. }
  66. return "本地文件解压成功";
  67. }
  68. /**
  69. * 压缩图片到web
  70. */
  71. @ApiOperation("压缩图片到web")
  72. @PostMapping("/web/compression")
  73. public String webCompressionDemo(HttpServletResponse response){
  74. Optional<CompressionStrategy<ImageDto>> best = compressionStrategies.stream()
  75. .filter(strategy -> strategy.support("demo.zip")).findFirst();
  76. if (best.isPresent()){
  77. try {
  78. // 压缩到指定输出流
  79. best.get().compression(tempData,response.getOutputStream());
  80. } catch (IOException e) {
  81. e.printStackTrace();
  82. return "web文件压缩异常";
  83. }
  84. }
  85. return "web文件压缩成功";
  86. }
  87. /**
  88. * 压缩图片到local
  89. */
  90. @ApiOperation("压缩图片到local")
  91. @PostMapping("/local/compression")
  92. public String localCompressionDemo(){
  93. // 获取当前项目文件夹的的zip文件
  94. String filePath = System.getProperty("user.dir")+"/demo-zip/src/main/resources/imageTest.zip";
  95. String fileName = filePath.substring(filePath.lastIndexOf('/')+1);
  96. try {
  97. OutputStream os = new FileOutputStream(new File(filePath));
  98. Optional<CompressionStrategy<ImageDto>> best = compressionStrategies.stream()
  99. .filter(strategy -> strategy.support(fileName)).findFirst();
  100. // 压缩到指定输出流
  101. if (best.isPresent()){
  102. best.get().compression(tempData,os);
  103. }
  104. } catch (IOException e) {
  105. e.printStackTrace();
  106. return "压缩图片到本地异常";
  107. }
  108. return "压缩图片到本地成功";
  109. }
  110. }

致谢

一直往前走,别往后看。顺其自然,内心就会逐渐清朗,时光越老,人心越淡。常怀宽容感激之心,宽容那就是一种美德是一种智慧,海纳百川是多么广阔,感激你的朋友,是他们给了你帮助;感激你的敌人,是他们是让你变的坚强。感谢你的阅读,你努力的样子很可爱呀。

Java压缩包(zip)【学习笔记】的更多相关文章

  1. 《深入理解Java虚拟机》学习笔记

    <深入理解Java虚拟机>学习笔记 一.走近Java JDK(Java Development Kit):包含Java程序设计语言,Java虚拟机,JavaAPI,是用于支持 Java 程 ...

  2. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  3. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  4. Java安全防御学习笔记V1.0

    Java安全防御学习笔记V1.0http://www.docin.com/p-766808938.html

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  7. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  8. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  9. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  10. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

随机推荐

  1. python集合的运算

    &  交集  | 并集    - 差集  ^ 异或集 # 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果 # 创建两个集合 s = {1,2,3,4,5} s2 = {3,4,5, ...

  2. H5录音音频可视化-实时波形频谱绘制、频率直方图

    这段时间给GitHub Recorder开源库添加了两个新的音频可视化功能,比以前单一的动态波形显示丰富了好多(下图后两行是不是比第一行看起来丰满些):趁热打铁写了一个音频可视化相关扩展测试代码,下面 ...

  3. vue vuex开发中遇到的问题及解决小技巧

    1.在vue的开发中,如果使用了vuex,数据的组装,修改时在mutations中,页面是建议修改变量值的,如果强制修改,控制台就会出现错误.如下: 这种错误虽然不会影响结果,但是是vuex不提倡的方 ...

  4. Python解析json字符串,json字符串用法

    json数据简介 json数据是一个轻量级的数据交换格式,采用完全独立于语言的文本格式,这些特性使json称为理想的数据交换语言,易于人阅读和编写,同时易于机器解析和生成. json中的字符集必须是U ...

  5. Tesseract-OCR-v5.0中文识别,训练自定义字库,提高图片的识别效果

    1,下载安装Tesseract-OCR 安装,链接地址https://digi.bib.uni-mannheim.de/tesseract/ ​ 2,安装成功 tesseract -v 注意:安装后, ...

  6. 从源码上理解Netty并发工具-Promise

    前提 最近一直在看Netty相关的内容,也在编写一个轻量级的RPC框架来练手,途中发现了Netty的源码有很多亮点,某些实现甚至可以用苛刻来形容.另外,Netty提供的工具类也是相当优秀,可以开箱即用 ...

  7. [bzoj1041] [洛谷P2508] [HAOI2008] 圆上的整点

    Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数. Input 只有一个正整数n,n<=2000 000 000 Output 整点个数 Samp ...

  8. Error:Cannot build artifact 'XXX:war exploded' because it is included into a circular dependency (artifact 'XXXX:war exploded', artifact 'XXX:war exploded') Idea启动项目报错解决方案

    在Idea中使用Maven创建父子工程,第一个Model的那个项目可以很好的运行,在创建一个Model运行时报这个错.原因是tomcat部署了多个Web项目,可能最开始是两个项目的配置文件混用用,最后 ...

  9. chrome最耐看的主题

    google chrome最耐看的主题James White大家可以尝试一下

  10. 6、python基本数据类型之序列类型

    前言:python的基本数据类型可以分为三类:数值类型.序列类型.散列类型,本文主要介绍序列类型及其通用操作. 一.序列类型 1)字符串(str):用单引号('),双引号("),三引号(三单 ...