Java使用基本JDK操作ZIP文件


提示:

本文简单介绍介绍了一下JDK中的zip接口,但JDK自带的zip操作接口非常不完善,既不支持中文,也不支持密码,所以可用性不高。

如果您有在Java语言环境中处理zip压缩文件的需要,推荐采用zip4j这一开源项目,zip4j支持多种加密和压缩算法,采用unicode编码,所以也支持中文,其它方面也是非常优秀,可以说是功能强大。

详见另一篇文章:

最近由于工作需要,对Java语言下的ZIP和RAR解压和压缩作了一些了解,现记录一下,以备不时之需,如果能帮到各位朋友,自是大佳。

首先说说ZIP格式:

JDK本身就已经提供了操作ZIP文件的接口(在java.util.zip包下),这些接口使用起来很简单,该包下主要涉及了

ZipEntry // 此类用于表示 ZIP 文件条目

ZipFile // 此类用于从 ZIP 文件读取条目

ZipInputStream // 此类为读取 ZIP 文件格式的文件实现输入流

ZipOutputStream // 此类为以 ZIP 文件格式写入文件实现输出流

等几个类,其它的类有些跟校验有关,还有一些不明白了,基本使用中没有用到。

其中ZipEntry代表ZIP文件中一条项目(包括目录和文件),ZipFile则表示一个zip压缩文件,ZipFile类中提供了获取其代表文件中的所有Entry的方法,通过这些方法我们可以取得第一条ZipEntry,该对象中有我们需要的信息,可以通过读写流操作将其从压缩文件中抽出,并写到本地磁盘,完成操作也就表示完成了ZIP文件的解压。

ZipInputStream 表示ZIP文件的输入流,通过该类也可以完成解压,其中也有获取ZipEntry的方法,同ZipFile类似可以通过流的读写完成解压。

ZipOutputStream 表示ZIP文件的输出流,可以完成ZIP压缩,也是通过其相关方法将新建ZipEntry(目录或文件)添加进输出流,然后同样通过流的读写将本地磁盘文件写进ZIP压缩文件(如果是目录则不需要流操作,仅需将ZipEntry添加进输出流即可),最后输出到磁盘。

在解压过程中有一个问题需要注意,就是压缩文件中含有目录嵌套这种情况,其实ZipEntry中有一个方法isDirectory(),但我试了一下,不论何种情况该方法都反回false,不知道是不是自己有什么 地方没有做对,于是就想用一种比较笨的方式创建目录:如果当前ZipEntry的name(可以能过getName()获得)以File.separator结尾说明该Entry是个目录,将其创建,如果不是则将其抽出。如果哪位有好的方式请赐教。

说多了也没啥用,个人理解也不是很透彻,下面是一个比较简单的示例,仅仅是几个API的使用,不过仍然简单地完成了压缩和解压缩,如果您在关注,希望能起到点抛砖引玉的作用。

JDK自带的ZIP包解压ZIP压缩文件:

package com.ninemax.demo.zip;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

/**
 * 压缩指定的文件或目录
 * 解压指定的压缩文件(仅限ZIP格式).
 * 采用JDK1.6,不依赖其它开源项目
 * @author zyh
 */
public class ZipUtil {
 /**
  * 将指定文件或者指定目录下的所有文件压缩并生成指定路径的压缩文件.
    * 如果压缩文件的路径或父路径不存在, 将会自动创建.
  * @param srcFile 将要进行压缩的文件或目录
  * @param destfFile 最终生成的压缩文件的路径
  * @throws IOException
  */
 public static void zipFile(String srcFile,String destFile) throws IOException {
  zipFile(new File(srcFile), new File(destFile));
 }
 
 /**
  * 将指定文件或目录下的所有文件压缩并生成指定路径的压缩文件.
    * 如果压缩文件的路径或父路径不存在, 将会自动创建.
  * @param srcFile 将要进行压缩的文件或目录
  * @param destFile 最终生成的压缩文件的路径
  * @throws IOException
  */
 public static void zipFile(File srcFile,File destFile) throws IOException {
  zipFile(srcFile, FileUtils.openOutputStream(destFile));
 }
 
 /**
  * 将指定文件或目录下的所有文件压缩并将流写入指定的输出流中.
    *
    * @param srcFile 将要进行压缩的目录
  * @param outputStream 用于接收压缩产生的文件流的输出流
  */
 private static void zipFile(File srcFile,OutputStream outputStream) {
  zipFile(srcFile, new ZipOutputStream(outputStream));
 }
 
    /**
    * 将指定目录下的所有文件压缩并将流写入指定的ZIP输出流中.
    *
    * @param srcFile 将要进行压缩的目录
    * @param zipOut 用于接收压缩产生的文件流的ZIP输出流
    */ 
 private static void zipFile(File srcFile,ZipOutputStream zipOut) {
  try {
   doZipFile(srcFile,zipOut, "");
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   IOUtils.closeQuietly(zipOut);
  }
 }

 /**
  * 压缩文件或目录到指定ZipOutputStream
  * @param srcFile 指定文件或者目录
  * @param zipOut 指定ZipOutputStream输出流
  * @param ns 文件组织到ZIP文件时的路径
  * @throws IOException
  */
 private static void doZipFile(File srcFile, ZipOutputStream zipOut,
   String ns) throws IOException {
  if (srcFile.isFile()) {
   zipOut.putNextEntry(new ZipEntry(ns + srcFile.getName()));
   InputStream is = FileUtils.openInputStream(srcFile);
   try {
    IOUtils.copy(is, zipOut);
   } catch (Exception e) {
    e.printStackTrace();
   } finally {
    IOUtils.closeQuietly(is);
   }
   return;
  }
  for (File file : srcFile.listFiles()) {
   String entryName = ns + file.getName();

   if (file.isDirectory()) {
    entryName += File.separator;
    zipOut.putNextEntry(new ZipEntry(entryName));
   }
   doZipFile(file, zipOut, entryName);
  }
 }
 
 /**
    * 将指定的压缩文件解压到指定的目标目录下.
    * 如果指定的目标目录不存在或其父路径不存在, 将会自动创建.
    *
    * @param zipFile 将会解压的压缩文件
    * @param destFile 解压操作的目录
    */
 public static void unzipFile(String zipFile,String destFile) throws IOException {
  unzipFile(new File(zipFile), new File(destFile));
 }
 
 /**
    * 将指定的压缩文件解压到指定的目标目录下.
    * 如果指定的目标目录不存在或其父路径不存在, 将会自动创建.
    *
    * @param zipFile 将会解压的压缩文件
    * @param destFile 解压操作的目录目录
    */
 public static void unzipFile(File zipFile,File destFile) throws IOException {
  unzipFile(FileUtils.openInputStream(zipFile), destFile);
//  doUnzipFile(new ZipFile(zipFile), destFile);
 }
 
 public static void doUnzipFile(ZipFile zipFile,File dest) throws IOException {
  if (!dest.exists()) {
   FileUtils.forceMkdir(dest);
  }
  Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zipFile.entries();
  while (entries.hasMoreElements()) {
   ZipEntry entry = entries.nextElement();
   File file = new File(dest, entry.getName());
   if (entry.getName().endsWith(File.separator)) {
    FileUtils.forceMkdir(file);
   } else {
    OutputStream out = FileUtils.openOutputStream(file);
    InputStream in = zipFile.getInputStream(entry);
    try {
     IOUtils.copy(in, out);
    } catch (Exception e) {
     e.printStackTrace();
    } finally {
     IOUtils.closeQuietly(out);
    }
   }
  }
  zipFile.close();
 }
 
    /**
    * 将指定的输入流解压到指定的目标目录下.
    *
    * @param is 将要解压的输入流
    * @param destFile 解压操作的目标目录
    * @throws IOException
    */ 
 public static void unzipFile(InputStream is,File destFile) throws IOException {
  try {
   if (is instanceof ZipInputStream) {
    doUnzipFile((ZipInputStream) is,destFile);
   } else {
    doUnzipFile(new ZipInputStream(is), destFile);
   }
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   IOUtils.closeQuietly(is);
  }
 }
 
 /**
  *
  * @param zipInput
  * @param dest
  * @throws IOException
  */
 private static void doUnzipFile(ZipInputStream zipInput, File dest)
   throws IOException {
  if (!dest.exists()) {
   FileUtils.forceMkdir(dest);
  }
  for (ZipEntry entry; (entry = zipInput.getNextEntry()) != null;) {
   String entryName = entry.getName();

   File file = new File(dest, entry.getName());
   if (entryName.endsWith(File.separator)) {
    FileUtils.forceMkdir(file);
   } else {
    OutputStream out = FileUtils.openOutputStream(file);
    try {
     IOUtils.copy(zipInput, out);
    } catch (Exception e) {
     e.printStackTrace();
    } finally {
     IOUtils.closeQuietly(out);
    }
   }
   zipInput.closeEntry();
  }
 }
 
 // 测试
 public static void main(String[] args) {
  try {
//   zipFile("M:\\ZIP\\test\\tempZIP", "M:\\ZIP\\test\\bbc.zip");
   unzipFile("M:\\ZIP\\test\\bbc.zip", "M:\\ZIP\\test\\bb\\");
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

注:
1、详细情况请参照JDK文档

2、JDK自身的ZIP包不支持中文,所以网上有很多介绍Apache下的解决方案,此处不作描述,文章太长了就更加臭了,另起一篇写。

3、不支持密码,网上另有支持密码的项目,如果可能,另起文章介绍吧!

Java操作带密码的ZIP文件请参照:

本文永久更新链接地址:

相关内容

    暂无相关文章