当前位置:首页 » JAVA技术教程

java zip工具类

2013-07-28 21:42 本站整理 浏览(2)
依赖jar :apache-ant-1.9.2-bin.zip
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * zip工具
 * 用于制作压缩包和解压包
 * @author Sun Qinbo
 * @version 1.0, 2013-7-26
 */
public class ZipUtils {
	private static final Logger log = LoggerFactory.getLogger(ZipUtils.class);
	private ZipOutputStream zipOut;
	private static byte[] buf = new byte[1024];

	/**
	 * 制作压缩包
	 */
	public static void zip(OutputStream out, List<FileEntry> fileEntrys, String encoding) {
		new ZipUtils(out, fileEntrys, encoding);
	}

	/**
	 * 制作压缩包
	 */
	public static void zip(OutputStream out, List<FileEntry> fileEntrys) {
		new ZipUtils(out, fileEntrys, null);
	}

	/**
	 * 根据源目录 制作压缩包
	 * @param srcFiles 源文件目录
	 * @param out 输出文件流
	 * @param filter 文件过滤,不过滤可以为null。
	 * @param parent 压缩包根目录名,不需要可以为null。
	 * @param prefix 文件前缀,不需要可以为null。
	 * @param encoding 编码 ,不设置取系统编码。
	 */

	public static void zip(File[] srcFiles, OutputStream out, FilenameFilter filter, String parent, String prefix, String encoding) {
		Assert.notEmpty(srcFiles);
		List<FileEntry> fileEntrys = new ArrayList<FileEntry>();
		for (int i = 0; i < srcFiles.length; i++) {
			FileEntry fileEntry = new FileEntry(parent, prefix, srcFiles[i], filter);
			fileEntrys.add(fileEntry);
		}
		new ZipUtils(out, fileEntrys, encoding);
	}

	/**
	 * 创建ZipUtils对象
	 * @param out 输出流
	 * @param filter 文件过滤,不过滤可以为null。
	 * @param fileEntrys 源文件名。可以有多个源文件,如果源文件是目录,那么所有子目录都将被包含。
	 */
	protected ZipUtils(OutputStream out, List<FileEntry> fileEntrys, String encoding) {
		Assert.notEmpty(fileEntrys);
		long begin = System.currentTimeMillis();
		log.debug("开始制作压缩包");
		try {
			try {
				zipOut = new ZipOutputStream(out);
				if (!StringUtils.isBlank(encoding)) {
					log.debug("using encoding: {}", encoding);
					zipOut.setEncoding(encoding);
				} else {
					log.debug("using default encoding");
				}
				for (FileEntry fe : fileEntrys) {
					zip(fe.getFile(), fe.getFilter(), fe.getZipEntry(), fe.getPrefix());
				}
			} finally {
				zipOut.close();
			}
		} catch (IOException e) {
			throw new RuntimeException("制作压缩包时,出现IO异常!", e);
		}
		long end = System.currentTimeMillis();
		log.info("制作压缩包成功。耗时:{}ms。", end - begin);
	}

	/**
	 * 压缩文件
	 * @param srcFile 源文件
	 * @param pentry 压缩包根目录名,不需要可以为null。
	 * @param prefix 文件前缀
	 * @throws IOException
	 */
	private void zip(File srcFile, FilenameFilter filter, ZipEntry pentry, String prefix) throws IOException {
		ZipEntry entry;
		if (srcFile.isDirectory()) {
			if (pentry == null) {
				entry = new ZipEntry(srcFile.getName());
			} else {
				entry = new ZipEntry(pentry.getName() + "/" + srcFile.getName());
			}
			File[] files = srcFile.listFiles(filter);
			for (File f : files) {
				zip(f, filter, entry, prefix);
			}
		} else {
			if (pentry == null) {
				entry = new ZipEntry(prefix + srcFile.getName());
			} else {
				entry = new ZipEntry(pentry.getName() + "/" + prefix + srcFile.getName());
			}
			FileInputStream in;
			try {
				log.debug("读取文件:{}", srcFile.getAbsolutePath());
				in = new FileInputStream(srcFile);
				try {
					zipOut.putNextEntry(entry);
					int len;
					while ((len = in.read(buf)) > 0) {
						zipOut.write(buf, 0, len);
					}
					zipOut.closeEntry();
				} finally {
					in.close();
				}
			} catch (FileNotFoundException e) {
				throw new RuntimeException("制作压缩包时,源文件不存在:" + srcFile.getAbsolutePath(), e);
			}
		}
	}

	/**
	 * 解压
	 * @param zipFile 压缩包文件
	 * @param destDir 压缩路径
	 * @param encoding
	 * @author Sun Qinbo
	 */
	public static void unzip(File zipFile, File destDir, String encoding) {
		long begin = System.currentTimeMillis();
		log.debug("开始解压缩包");
		if (destDir.exists() && !destDir.isDirectory()) {
			throw new IllegalArgumentException("destDir is not a directory!");
		}
		ZipFile zip = null;
		InputStream is = null;
		FileOutputStream fos = null;
		File file;
		String name;
		int readed;
		ZipEntry entry;
		try {
			try {
				if (StringUtils.isNotBlank(encoding)) {
					zip = new ZipFile(zipFile, encoding);
				} else {
					zip = new ZipFile(zipFile);
				}
				Enumeration<?> en = zip.getEntries();
				while (en.hasMoreElements()) {
					entry = (ZipEntry) en.nextElement();
					name = entry.getName();
					name = name.replace('/', File.separatorChar);
					file = new File(destDir, name);
					if (entry.isDirectory()) {
						file.mkdirs();
					} else {
						// 创建父目录
						file.getParentFile().mkdirs();
						is = zip.getInputStream(entry);
						fos = new FileOutputStream(file);
						while ((readed = is.read(buf)) > 0) {
							fos.write(buf, 0, readed);
						}
						fos.close();
						is.close();
					}
				}
			} finally {
				if (fos != null) {
					fos.close();
				}
				if (is != null) {
					is.close();
				}
				if (zip != null) {
					zip.close();
				}
			}
		} catch (IOException e) {
			log.error("", e);
		}
		long end = System.currentTimeMillis();
		log.info("解压缩包成功。耗时:{}ms。", end - begin);

	}

	/** 测试 */
	public static void main(String[] args) throws IOException {
		List<FileEntry> fileEntrys = new ArrayList<FileEntry>();
		File[] listFiles = new File("d://test").listFiles();
		for (int i = 0; i < listFiles.length; i++) {
			fileEntrys.add(new FileEntry("", "", listFiles[i]));
		}
		ZipUtils.zip(new FileOutputStream("D://测试_1.zip"), fileEntrys);
		ZipUtils.zip(new File("d://test").listFiles(), new FileOutputStream("D://测试_2.zip"), null, "自定义根目录", "自定义前缀_", "UTF-8");
		ZipUtils.unzip(new File("D://测试_2.zip"), new File("D://测试_2"), null);
	}

	/**
	 * 源文件自定义类型
	 */
	public static class FileEntry {
		private FilenameFilter filter;
		private String parent; // 压缩包内的目录名
		private File file;
		private String prefix; // 压缩文件前缀

		public FileEntry(String parent, String prefix, File file, FilenameFilter filter) {
			this.parent = parent;
			this.prefix = prefix;
			this.file = file;
			this.filter = filter;
		}

		/**
		 * @param parent 压缩包内的目录名
		 * @param file 压缩文件前缀
		 */
		public FileEntry(String parent, File file) {
			this.parent = parent;
			this.file = file;
		}

		public FileEntry(String parent, String prefix, File file) {
			this(parent, prefix, file, null);
		}

		public ZipEntry getZipEntry() {
			if (StringUtils.isBlank(parent)) {
				return null;
			} else {
				return new ZipEntry(parent);
			}
		}

		public FilenameFilter getFilter() {
			return filter;
		}

		public void setFilter(FilenameFilter filter) {
			this.filter = filter;
		}

		public String getParent() {
			return parent;
		}

		public void setParent(String parent) {
			this.parent = parent;
		}

		public File getFile() {
			return file;
		}

		public void setFile(File file) {
			this.file = file;
		}

		public String getPrefix() {
			if (prefix == null) {
				return "";
			} else {
				return prefix;
			}
		}

		public void setPrefix(String prefix) {
			this.prefix = prefix;
		}
	}
}