原文:http://snowolf.iteye.com/blog/642298

去年整理了一篇ZLib算法Java实现(Java压缩技术(一) ZLib),一直惦记却没时间补充。今天得空,整理一下ZIP的java原生实现。
看了几篇zip压缩算法的帖子,讲的算是比较细致了,但就是没有对应的解压缩实现,太惜败了! 我就喜欢没事做总结,稍作整理,将其收纳!

相关链接:

Java压缩技术(一) ZLib

Java压缩技术(二) ZIP压缩——Java原生实现

Java压缩技术(三) ZIP解压缩——Java原生实现

Java压缩技术(四) GZIP——Java原生实现

Java压缩技术(五) GZIP相关——浏览器解析

Java压缩技术(六) BZIP2——Commons实现

Java压缩技术(七) TAR——Commons实现

查过相关资料后才知道,ZIP应该算作归档类的压缩算法,每一门学科都可深可浅!

闲言少叙,先说ZIP压缩。

zip压缩需要通过ZipOutputStream 执行write方法将压缩数据写到指定输出流中。

注意,这里应先使用CheckedOutputStream 指定文件校验算法。(通常使用CRC32算法)。代码如下所示:

  1. CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(destPath), new CRC32());
  2. ZipOutputStream zos = new ZipOutputStream(cos);

接下来,需要将待压缩文件以ZipEntry的方式追加到压缩文件中,如下所示:

  1. /**
  2. * 压缩包内文件名定义
  3. *
  4. * <pre>
  5. * 如果有多级目录,那么这里就需要给出包含目录的文件名
  6. * 如果用WinRAR打开压缩包,中文名将显示为乱码
  7. * </pre>
  8. */
  9. ZipEntry entry = new ZipEntry(dir + file.getName());
  10. zos.putNextEntry(entry);

ZipEntry就是压缩包中的每一个实体!

完成上述准备后,就可以执行压缩操作了。实际上,就是执行ZipOutputStream类的write方法,如下所示:

  1. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
  2. file));
  3. int count;
  4. byte data[] = new byte[BUFFER];
  5. while ((count = bis.read(data, 0, BUFFER)) != -1) {
  6. zos.write(data, 0, count);
  7. }
  8. bis.close();

当然,如果待添加的压缩项是一个目录。那么,需要通过递归的方式指定最终的压缩项。

如果要添加一个空目录,注意使用符号"/"(String PATH="/";)作为添加项名字结尾符!

递归构建目录压缩,代码如下:

  1. /**
  2. * 压缩
  3. *
  4. * @param srcFile
  5. *            源路径
  6. * @param zos
  7. *            ZipOutputStream
  8. * @param basePath
  9. *            压缩包内相对路径
  10. * @throws Exception
  11. */
  12. private static void compress(File srcFile, ZipOutputStream zos,
  13. String basePath) throws Exception {
  14. if (srcFile.isDirectory()) {
  15. compressDir(srcFile, zos, basePath);
  16. } else {
  17. compressFile(srcFile, zos, basePath);
  18. }
  19. }
  20. /**
  21. * 压缩目录
  22. *
  23. * @param dir
  24. * @param zos
  25. * @param basePath
  26. * @throws Exception
  27. */
  28. private static void compressDir(File dir, ZipOutputStream zos,
  29. String basePath) throws Exception {
  30. File[] files = dir.listFiles();
  31. // 构建空目录
  32. if (files.length < 1) {
  33. ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);
  34. zos.putNextEntry(entry);
  35. zos.closeEntry();
  36. }
  37. for (File file : files) {
  38. // 递归压缩
  39. compress(file, zos, basePath + dir.getName() + PATH);
  40. }
  41. }

x是一个空目录,用WinRAR打开后,可以看到这个目录下还有一个空文件名文件!

来个完整的压缩实现,代码如下所示:

  1. /**
  2. * 2010-4-12
  3. */
  4. package org.zlex.commons.io;
  5. import java.io.BufferedInputStream;
  6. import java.io.BufferedOutputStream;
  7. import java.io.File;
  8. import java.io.FileInputStream;
  9. import java.io.FileOutputStream;
  10. import java.util.zip.CRC32;
  11. import java.util.zip.CheckedInputStream;
  12. import java.util.zip.CheckedOutputStream;
  13. import java.util.zip.ZipEntry;
  14. import java.util.zip.ZipInputStream;
  15. import java.util.zip.ZipOutputStream;
  16. /**
  17. * ZIP压缩工具
  18. *
  19. * @author  <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
  20. * @since 1.0
  21. */
  22. public class ZipUtils {
  23. public static final String EXT = ".zip";
  24. private static final String BASE_DIR = "";
  25. // 符号"/"用来作为目录标识判断符
  26. private static final String PATH = "/";
  27. private static final int BUFFER = 1024;
  28. /**
  29. * 压缩
  30. *
  31. * @param srcFile
  32. * @throws Exception
  33. */
  34. public static void compress(File srcFile) throws Exception {
  35. String name = srcFile.getName();
  36. String basePath = srcFile.getParent();
  37. String destPath = basePath + name + EXT;
  38. compress(srcFile, destPath);
  39. }
  40. /**
  41. * 压缩
  42. *
  43. * @param srcFile
  44. *            源路径
  45. * @param destPath
  46. *            目标路径
  47. * @throws Exception
  48. */
  49. public static void compress(File srcFile, File destFile) throws Exception {
  50. // 对输出文件做CRC32校验
  51. CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(
  52. destFile), new CRC32());
  53. ZipOutputStream zos = new ZipOutputStream(cos);
  54. compress(srcFile, zos, BASE_DIR);
  55. zos.flush();
  56. zos.close();
  57. }
  58. /**
  59. * 压缩文件
  60. *
  61. * @param srcFile
  62. * @param destPath
  63. * @throws Exception
  64. */
  65. public static void compress(File srcFile, String destPath) throws Exception {
  66. compress(srcFile, new File(destPath));
  67. }
  68. /**
  69. * 压缩
  70. *
  71. * @param srcFile
  72. *            源路径
  73. * @param zos
  74. *            ZipOutputStream
  75. * @param basePath
  76. *            压缩包内相对路径
  77. * @throws Exception
  78. */
  79. private static void compress(File srcFile, ZipOutputStream zos,
  80. String basePath) throws Exception {
  81. if (srcFile.isDirectory()) {
  82. compressDir(srcFile, zos, basePath);
  83. } else {
  84. compressFile(srcFile, zos, basePath);
  85. }
  86. }
  87. /**
  88. * 压缩
  89. *
  90. * @param srcPath
  91. * @throws Exception
  92. */
  93. public static void compress(String srcPath) throws Exception {
  94. File srcFile = new File(srcPath);
  95. compress(srcFile);
  96. }
  97. /**
  98. * 文件压缩
  99. *
  100. * @param srcPath
  101. *            源文件路径
  102. * @param destPath
  103. *            目标文件路径
  104. *
  105. */
  106. public static void compress(String srcPath, String destPath)
  107. throws Exception {
  108. File srcFile = new File(srcPath);
  109. compress(srcFile, destPath);
  110. }
  111. /**
  112. * 压缩目录
  113. *
  114. * @param dir
  115. * @param zos
  116. * @param basePath
  117. * @throws Exception
  118. */
  119. private static void compressDir(File dir, ZipOutputStream zos,
  120. String basePath) throws Exception {
  121. File[] files = dir.listFiles();
  122. // 构建空目录
  123. if (files.length < 1) {
  124. ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);
  125. zos.putNextEntry(entry);
  126. zos.closeEntry();
  127. }
  128. for (File file : files) {
  129. // 递归压缩
  130. compress(file, zos, basePath + dir.getName() + PATH);
  131. }
  132. }
  133. /**
  134. * 文件压缩
  135. *
  136. * @param file
  137. *            待压缩文件
  138. * @param zos
  139. *            ZipOutputStream
  140. * @param dir
  141. *            压缩文件中的当前路径
  142. * @throws Exception
  143. */
  144. private static void compressFile(File file, ZipOutputStream zos, String dir)
  145. throws Exception {
  146. /**
  147. * 压缩包内文件名定义
  148. *
  149. * <pre>
  150. * 如果有多级目录,那么这里就需要给出包含目录的文件名
  151. * 如果用WinRAR打开压缩包,中文名将显示为乱码
  152. * </pre>
  153. */
  154. ZipEntry entry = new ZipEntry(dir + file.getName());
  155. zos.putNextEntry(entry);
  156. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
  157. file));
  158. int count;
  159. byte data[] = new byte[BUFFER];
  160. while ((count = bis.read(data, 0, BUFFER)) != -1) {
  161. zos.write(data, 0, count);
  162. }
  163. bis.close();
  164. zos.closeEntry();
  165. }
  166. }

来做个简单的测试:

  1. import static org.junit.Assert.*;
  2. import org.junit.Test;
  3. /**
  4. *
  5. * @author 梁栋
  6. * @version 1.0
  7. * @since 1.0
  8. */
  9. public class ZipUtilsTest {
  10. /**
  11. *
  12. */
  13. @Test
  14. public void test() throws Exception {
  15. // 压缩文件
  16. ZipUtils.compress("d:\\f.txt");
  17. // 压缩目录
  18. ZipUtils.compress("d:\\fd");
  19. }
  20. }

现在用WinRAR打开看看,是不是效果几乎一致?

当然,上述代码有所不足之处主要是中文名称乱码问题。用java原生ZIP实现压缩后得到的压缩包,与系统的字符集不同,文件/目录名将出现乱码。这是所有归档压缩都会遇到的问题。对于这种问题,Commons Copress提供了解决方案!

对于解压缩,请关注后续内容!

Java压缩技术(二) ZIP压缩——Java原生实现的更多相关文章

  1. Java虚拟机(二):Java GC算法 垃圾收集器

    概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方 ...

  2. 赶紧收藏!王者级别的Java多线程技术笔记,我java小菜鸡愿奉你为地表最强!

    Java多线程技术概述 介绍多线程之前要介绍线程,介绍线程则离不开进程. 首先 , 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元: 线程:就 ...

  3. Java并发(二):Java内存模型

    一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...

  4. Java学习笔记二十八:Java中的接口

    Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...

  5. 夯实Java基础(二十)——JAVA正则表达式

    1.为什么要用正则表达式 首先我们先来做一道题目:判断一个字符串是否由数字组成.代码示例如下: public class Test { public static void main(String[] ...

  6. 手写JAVA虚拟机(二)——实现java命令行

    查看手写JAVA虚拟机系列可以进我的博客园主页查看. 我们知道,我们编译.java并运行.class文件时,需要一些java命令,如最简单的helloworld程序. 这里的程序最好不要加包名,因为加 ...

  7. JAVA实现实用的ZIP压缩与解压

    http://blog.csdn.net/z69183787/article/details/38555913

  8. java 深入技术二(Collection)

    1. java集合 存储和管理多个java对象 包括很多java类和接口 Collection List                              Set ArrayList  Lin ...

  9. 再回首,Java温故知新(二):Java基本数据类型

    Java作为一种强类型语言,意味着每一个变量都会有特定的类型,Java共有8种基本类型,其中有4种整型(byte.short.int.long).两种浮点型(float.double).1种字符型(c ...

  10. 深入理解java虚拟机(二)HotSpot Java对象创建,内存布局以及访问方式

    内存中对象的创建.对象的结构以及访问方式. 一.对象的创建 在语言层面上,对象的创建只不过是一个new关键字而已,那么在虚拟机中又是一个怎样的过程呢? (一)判断类是否加载.虚拟机遇到一条new指令的 ...

随机推荐

  1. 【sqli-labs】 less48 GET -Error based -Blind -Numeric -Order By Clause(GET型基于盲注的整型Order By从句注入)

    图片还是47...访问的的确是48 这个是基于bool的盲注 http://192.168.136.128/sqli-labs-master/Less-48/?sort=1 and sleep(0.1 ...

  2. (转)学习淘淘商城第二十二课(KindEditor富文本编辑器的使用)

    http://blog.csdn.net/u012453843/article/details/70184155 上节课我们一起学习了怎样解决KindEditor富文本编辑器上传图片的浏览器兼容性问题 ...

  3. HDU_1068_Girls and Boys_二分图匹配

    Girls and Boys Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. Oreacle 语句

    SELECT * FROM = and CREATETIME >to_date('2019-01-01' , 'yyyy-mm-dd hh24:mi:ss') and CREATETIME &l ...

  5. C# 统计字符串出现的个数

    string str1 = "123AAA456AAAA789AAAAAAA1011"; string str2 = "123456789AAA23456789AAAA3 ...

  6. 用jquery-easyui的布局layout写后台管理页面

    先在官网下载easyui文档 引入头部文件 <link rel="stylesheet" type="text/css" href="${pag ...

  7. sql的四种连接方式

    1.内联接.(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接. 内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行.例如,检索 students ...

  8. Problem 21

    Problem 21 https://projecteuler.net/problem=21 Let d(n) be defined as the sum of proper divisors of  ...

  9. 基本数据类型:布尔型(bool)和空值None

    一.布尔型(bool) 布尔类型很简单,就两个值 ,一个True(真),一个False(假), 主要用记逻辑判断: 一件事情成立就是True,不成立就是False,也可以将bool值归类为数字, 是因 ...

  10. ansible plugins 列表

    [action plugins] [cache plugins]jsonfilememcachedmemorymongodbpickleredisyaml [callback plugins]acti ...