原文: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. dotnetnuke 头像调用 头像缩放

    public static string GetProfileImage(int userId, int width, int height)        {                     ...

  2. 【译】x86程序员手册09-第3章程序指令集

    注:觉得本章内容与理解操作系统不直接相关,所以本章并未看完,也就没有翻译完,放在这里中是为了保证手册的完整.有兴趣的人可以去原址查看. https://pdos.csail.mit.edu/6.828 ...

  3. C# 设定时间内自动关闭提示框

    通过程序来自动关闭这个消息对话框而不是由用户点击确认按钮来关闭.然而.Net framework 没有为我们提供自动关闭MessageBox 的方法,要实现这个功能,我们需要使用Window API ...

  4. PAC代理语法含义与书写规范

    一直以来使用ShadowSocksFQ,基本上默认的PAC代理模式己能满足所需,实在个别pac不方便的就转成用全局代理模式也能愉快FQ. 只是最近学习前端的知识,需要FQ访问 MDN web docs ...

  5. JavaScript day3(数据类型)

    数据类型(data type) JavaScript提供七种不同的数据类型(data types),它们是string(字符串), symbol(符号), number(数字), undefined( ...

  6. 使用Robo 3T 软件管理MongoDB数据库如何执行命令行shell

    比如使用命令行的方式查看数据库runoobdb中的sites集合(数据表)中的所有数据 1.在连接名的地方鼠标右键选择“open shell” 2.在出现的shell窗口中输入一下命令行,然后按ctr ...

  7. The meaning of the number displayed on the man page in Linux

    0 Header files 0p Header files (POSIX) 1 Executable programs or shell commands 1p Executable program ...

  8. Silverlight之我见——DataGrid数据验证

    <UserControl x:Class="DataValidationSample.MainPage" xmlns="http://schemas.microso ...

  9. String formatting in Python

    | \n | 换行   || \t | 制表符 || \  | 转义   || \\ | \      | the '%' operator is used to format a set of va ...

  10. 【codeforces 796A】Buying A House

    [题目链接]:http://codeforces.com/contest/796/problem/A [题意] 让你选一个最靠近女票的,且能买的房子; 输出你和你女票的距离; [题解] 枚举 [Num ...