Java压缩技术(二) ZIP压缩——Java原生实现
原文: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算法)。代码如下所示:
- CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(destPath), new CRC32());
- ZipOutputStream zos = new ZipOutputStream(cos);
接下来,需要将待压缩文件以ZipEntry的方式追加到压缩文件中,如下所示:
- /**
- * 压缩包内文件名定义
- *
- * <pre>
- * 如果有多级目录,那么这里就需要给出包含目录的文件名
- * 如果用WinRAR打开压缩包,中文名将显示为乱码
- * </pre>
- */
- ZipEntry entry = new ZipEntry(dir + file.getName());
- zos.putNextEntry(entry);
ZipEntry就是压缩包中的每一个实体!
完成上述准备后,就可以执行压缩操作了。实际上,就是执行ZipOutputStream类的write方法,如下所示:
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- zos.write(data, 0, count);
- }
- bis.close();
当然,如果待添加的压缩项是一个目录。那么,需要通过递归的方式指定最终的压缩项。
如果要添加一个空目录,注意使用符号"/"(String PATH="/";)作为添加项名字结尾符!
递归构建目录压缩,代码如下:
- /**
- * 压缩
- *
- * @param srcFile
- * 源路径
- * @param zos
- * ZipOutputStream
- * @param basePath
- * 压缩包内相对路径
- * @throws Exception
- */
- private static void compress(File srcFile, ZipOutputStream zos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- compressDir(srcFile, zos, basePath);
- } else {
- compressFile(srcFile, zos, basePath);
- }
- }
- /**
- * 压缩目录
- *
- * @param dir
- * @param zos
- * @param basePath
- * @throws Exception
- */
- private static void compressDir(File dir, ZipOutputStream zos,
- String basePath) throws Exception {
- File[] files = dir.listFiles();
- // 构建空目录
- if (files.length < 1) {
- ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);
- zos.putNextEntry(entry);
- zos.closeEntry();
- }
- for (File file : files) {
- // 递归压缩
- compress(file, zos, basePath + dir.getName() + PATH);
- }
- }
x是一个空目录,用WinRAR打开后,可以看到这个目录下还有一个空文件名文件!
来个完整的压缩实现,代码如下所示:
- /**
- * 2010-4-12
- */
- package org.zlex.commons.io;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.util.zip.CRC32;
- import java.util.zip.CheckedInputStream;
- import java.util.zip.CheckedOutputStream;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipInputStream;
- import java.util.zip.ZipOutputStream;
- /**
- * ZIP压缩工具
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
- * @since 1.0
- */
- public class ZipUtils {
- public static final String EXT = ".zip";
- private static final String BASE_DIR = "";
- // 符号"/"用来作为目录标识判断符
- private static final String PATH = "/";
- private static final int BUFFER = 1024;
- /**
- * 压缩
- *
- * @param srcFile
- * @throws Exception
- */
- public static void compress(File srcFile) throws Exception {
- String name = srcFile.getName();
- String basePath = srcFile.getParent();
- String destPath = basePath + name + EXT;
- compress(srcFile, destPath);
- }
- /**
- * 压缩
- *
- * @param srcFile
- * 源路径
- * @param destPath
- * 目标路径
- * @throws Exception
- */
- public static void compress(File srcFile, File destFile) throws Exception {
- // 对输出文件做CRC32校验
- CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(
- destFile), new CRC32());
- ZipOutputStream zos = new ZipOutputStream(cos);
- compress(srcFile, zos, BASE_DIR);
- zos.flush();
- zos.close();
- }
- /**
- * 压缩文件
- *
- * @param srcFile
- * @param destPath
- * @throws Exception
- */
- public static void compress(File srcFile, String destPath) throws Exception {
- compress(srcFile, new File(destPath));
- }
- /**
- * 压缩
- *
- * @param srcFile
- * 源路径
- * @param zos
- * ZipOutputStream
- * @param basePath
- * 压缩包内相对路径
- * @throws Exception
- */
- private static void compress(File srcFile, ZipOutputStream zos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- compressDir(srcFile, zos, basePath);
- } else {
- compressFile(srcFile, zos, basePath);
- }
- }
- /**
- * 压缩
- *
- * @param srcPath
- * @throws Exception
- */
- public static void compress(String srcPath) throws Exception {
- File srcFile = new File(srcPath);
- compress(srcFile);
- }
- /**
- * 文件压缩
- *
- * @param srcPath
- * 源文件路径
- * @param destPath
- * 目标文件路径
- *
- */
- public static void compress(String srcPath, String destPath)
- throws Exception {
- File srcFile = new File(srcPath);
- compress(srcFile, destPath);
- }
- /**
- * 压缩目录
- *
- * @param dir
- * @param zos
- * @param basePath
- * @throws Exception
- */
- private static void compressDir(File dir, ZipOutputStream zos,
- String basePath) throws Exception {
- File[] files = dir.listFiles();
- // 构建空目录
- if (files.length < 1) {
- ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);
- zos.putNextEntry(entry);
- zos.closeEntry();
- }
- for (File file : files) {
- // 递归压缩
- compress(file, zos, basePath + dir.getName() + PATH);
- }
- }
- /**
- * 文件压缩
- *
- * @param file
- * 待压缩文件
- * @param zos
- * ZipOutputStream
- * @param dir
- * 压缩文件中的当前路径
- * @throws Exception
- */
- private static void compressFile(File file, ZipOutputStream zos, String dir)
- throws Exception {
- /**
- * 压缩包内文件名定义
- *
- * <pre>
- * 如果有多级目录,那么这里就需要给出包含目录的文件名
- * 如果用WinRAR打开压缩包,中文名将显示为乱码
- * </pre>
- */
- ZipEntry entry = new ZipEntry(dir + file.getName());
- zos.putNextEntry(entry);
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- zos.write(data, 0, count);
- }
- bis.close();
- zos.closeEntry();
- }
- }
来做个简单的测试:
- import static org.junit.Assert.*;
- import org.junit.Test;
- /**
- *
- * @author 梁栋
- * @version 1.0
- * @since 1.0
- */
- public class ZipUtilsTest {
- /**
- *
- */
- @Test
- public void test() throws Exception {
- // 压缩文件
- ZipUtils.compress("d:\\f.txt");
- // 压缩目录
- ZipUtils.compress("d:\\fd");
- }
- }
现在用WinRAR打开看看,是不是效果几乎一致?
当然,上述代码有所不足之处主要是中文名称乱码问题。用java原生ZIP实现压缩后得到的压缩包,与系统的字符集不同,文件/目录名将出现乱码。这是所有归档压缩都会遇到的问题。对于这种问题,Commons Copress提供了解决方案!
对于解压缩,请关注后续内容!
Java压缩技术(二) ZIP压缩——Java原生实现的更多相关文章
- Java虚拟机(二):Java GC算法 垃圾收集器
概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方 ...
- 赶紧收藏!王者级别的Java多线程技术笔记,我java小菜鸡愿奉你为地表最强!
Java多线程技术概述 介绍多线程之前要介绍线程,介绍线程则离不开进程. 首先 , 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元: 线程:就 ...
- Java并发(二):Java内存模型
一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...
- Java学习笔记二十八:Java中的接口
Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...
- 夯实Java基础(二十)——JAVA正则表达式
1.为什么要用正则表达式 首先我们先来做一道题目:判断一个字符串是否由数字组成.代码示例如下: public class Test { public static void main(String[] ...
- 手写JAVA虚拟机(二)——实现java命令行
查看手写JAVA虚拟机系列可以进我的博客园主页查看. 我们知道,我们编译.java并运行.class文件时,需要一些java命令,如最简单的helloworld程序. 这里的程序最好不要加包名,因为加 ...
- JAVA实现实用的ZIP压缩与解压
http://blog.csdn.net/z69183787/article/details/38555913
- java 深入技术二(Collection)
1. java集合 存储和管理多个java对象 包括很多java类和接口 Collection List Set ArrayList Lin ...
- 再回首,Java温故知新(二):Java基本数据类型
Java作为一种强类型语言,意味着每一个变量都会有特定的类型,Java共有8种基本类型,其中有4种整型(byte.short.int.long).两种浮点型(float.double).1种字符型(c ...
- 深入理解java虚拟机(二)HotSpot Java对象创建,内存布局以及访问方式
内存中对象的创建.对象的结构以及访问方式. 一.对象的创建 在语言层面上,对象的创建只不过是一个new关键字而已,那么在虚拟机中又是一个怎样的过程呢? (一)判断类是否加载.虚拟机遇到一条new指令的 ...
随机推荐
- Java_Web三大框架之Struts2
今天正式接触Java_Web三大框架之Struts2框架.对于初学者来说,先来了解什么是框架技术: 一.“框架技术”帮我们更快更好地构建程序: 1.是一个应用程序的半成品 2.提供可重用的公共结构 3 ...
- 用C#在Visual Studio写Javascript单元测试
1.在vs创建一个标准的单元测试工程 2.引用nuget包:Edge.js 我是用的是6.11.2版本 3.编写JsRunner类 using EdgeJs; using System; using ...
- 【原】PHPExcel导出Excel
1.引入相关公共库PHPExcel 2.编写公共函数 public function exportExcel($excelTitle,$data,$filename='',$column_width= ...
- flask之配置文件的加载和动态url的使用
七行代码实现一个flask app from flask import Flask app = Flask(__name__) @app.route('/') def helloworld(): re ...
- Aizu - 1379 Parallel Lines
平行直线 题意:给出一些点,这些点两两相连成一条直线,问最多能连成多少条直线. 思路:暴力出奇迹!!记得当时比赛做这道题的时候一直依赖于板子,结果却限制了自己的思路,这得改.dfs直接暴力,但是需要将 ...
- PHP基础库及扩展库安装
一.安装PHP所需的lib库(基础库): 1.yum install zlib-devel libxml2-devel libjpey-devel libjpeg-turbo-devel libico ...
- 20.混合使用match和近似匹配实现召回率与精准度的平衡
主要知识点: 召回率的慨念 精准度的慨念 match和近似匹配混合使用方法 召回率(recall):比如你搜索一个java spark,总共有100个doc,能返回多少个doc作为结果 ...
- 对SHH的公钥和私钥的简单理解
SSH是在应用层和传输层基础上的安全协议 SSH提供了两种级别的安全验证: 第一基于密码的安全验证:账号.密码,但可能有别的服务器冒充真正的服务器,无法避免被“中间人”攻击(man-in-the-mi ...
- [网络流24题#9] [cogs734] 方格取数 [网络流,最大流最小割]
将网格分为两部分,方法是黑白染色,即判断(i+j)&1即可,分开后从白色格子向黑色格子连边,每个点需要四条(边界点可能更少),也就是每个格子周围的四个方向.之后将源点和汇点分别于黑白格子连边, ...
- 树网的核(codevs 1167)
题目描述 Description [问题描述]设 T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T 为树网(treenetwork),其中V, E分别表 ...