Java文件压缩与解压
JAVA压缩与解压
需要的jar包
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>java-unrar</artifactId>
<version>1.7.0-3</version>
</dependency>
package com.util.base;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import de.innosystec.unrar.Archive;
import de.innosystec.unrar.NativeStorage;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;
/**
* 打包与解压操作类
* @author zhanglang
* 2018-09-26
*/
public class ZipUtil {
/**
* 递归压缩文件夹
* @param srcRootDir 压缩文件夹根目录的子路径
* @param file 当前递归压缩的文件或目录对象
* @param zos 压缩文件存储对象
* @throws Exception
*/
private static void zip(String srcRootDir, File file, ZipOutputStream zos) throws Exception {
if (file == null){
return;
}
//如果是文件,则直接压缩该文件
if (file.isFile()){
int count, bufferLen = 2048;
byte data[] = new byte[bufferLen];
//获取文件相对于压缩文件夹根目录的子路径
String subPath = file.getAbsolutePath();
int index = subPath.indexOf(srcRootDir);
if (index != -1){
subPath = subPath.substring(srcRootDir.length() + File.separator.length());
}
ZipEntry entry = new ZipEntry(subPath);
zos.putNextEntry(entry);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
while ((count = bis.read(data, 0, bufferLen)) != -1){
zos.write(data, 0, count);
}
bis.close();
zos.closeEntry();
} else {
//如果是目录,则压缩整个目录
//压缩目录中的文件或子目录
File[] childFileList = file.listFiles();
if(childFileList != null) {
for (int n=0; n<childFileList.length; n++){
childFileList[n].getAbsolutePath().indexOf(file.getAbsolutePath());
zip(srcRootDir, childFileList[n], zos);
}
}
}
}
/**
* 对文件或文件目录进行压缩
* @param srcPath 要压缩的源文件路径。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径
* @param zipPath 压缩文件保存的路径。注意:zipPath不能是srcPath路径下的子文件夹
* @param zipFileName 压缩文件名
* @throws Exception
*/
public static void zip(String srcPath, String zipPath, String zipFileName) throws Exception {
if (StringUtils.isEmpty(srcPath)
|| StringUtils.isEmpty(zipPath)
|| StringUtils.isEmpty(zipFileName)){
throw new TzException("Parameter null error.");
}
CheckedOutputStream cos = null;
ZipOutputStream zos = null;
try{
File srcFile = new File(srcPath);
//判断压缩文件保存的路径是否为源文件路径的子文件夹,如果是,则抛出异常(防止无限递归压缩的发生)
if (srcFile.isDirectory() && zipPath.indexOf(srcPath)!=-1){
throw new TzException("zipPath must not be the child directory of srcPath.");
}
//判断压缩文件保存的路径是否存在,如果不存在,则创建目录
File zipDir = new File(zipPath);
if (!zipDir.exists() || !zipDir.isDirectory()){
zipDir.mkdirs();
}
//创建压缩文件保存的文件对象
String zipFilePath = zipPath + (zipPath.endsWith(File.separator) ? "" : File.separator) + zipFileName;
File zipFile = new File(zipFilePath);
if (zipFile.exists()){
//检测文件是否允许删除,如果不允许删除,将会抛出SecurityException
// SecurityManager securityManager = new SecurityManager();
// securityManager.checkDelete(zipFilePath);
//删除已存在的目标文件
zipFile.delete();
}
cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());
zos = new ZipOutputStream(cos);
//如果只是压缩一个文件,则需要截取该文件的父目录
String srcRootDir = srcPath;
if (srcFile.isFile()){
int index = srcPath.lastIndexOf(File.separator);
if (index != -1){
srcRootDir = srcPath.substring(0, index);
}
}
//调用递归压缩方法进行目录或文件压缩
zip(srcRootDir, srcFile, zos);
zos.flush();
} catch (Exception e){
throw e;
} finally {
try{
if (zos != null){
zos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 解压缩zip包
* @param zipFilePath zip文件的全路径
* @param unzipFilePath 解压后的文件保存的路径
*/
@SuppressWarnings("unchecked")
public static void unZip(String zipFilePath, String unzipFilePath)
throws TzException {
if (StringUtils.isEmpty(zipFilePath)
|| StringUtils.isEmpty(unzipFilePath)){
throw new TzException("参数错误");
}
File zipFile = new File(zipFilePath);
if (!zipFile.exists()) {
throw new TzException(zipFile.getPath() + "所指文件不存在");
}
//创建解压缩文件保存的路径
File unzipFileDir = new File(unzipFilePath);
if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()){
unzipFileDir.mkdirs();
}
if (zipFilePath.toLowerCase().endsWith(".rar")) {
unRar(zipFilePath, unzipFilePath);
}else {
if (!zipFilePath.toLowerCase().endsWith(".zip")) {
throw new TzException("文件不是zip压缩文件");
}
//开始解压
int count = 0, bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
ZipFile zip = null;
try {
zip = new ZipFile(zipFile, Charset.forName("GBK"));
Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>)zip.entries();
//循环对压缩包里的每一个文件进行解压
while(entries.hasMoreElements()){
ZipEntry entry = entries.nextElement();
if (entry.isDirectory()) {
String dirPath = unzipFilePath + File.separator + entry.getName();
File dir = new File(dirPath);
//如果文件夹路径不存在,则创建文件夹
if (!dir.exists()){
dir.mkdirs();
}
} else {
//构建压缩包中一个文件解压后保存的文件全路径
String entryFilePath = unzipFilePath + File.separator + entry.getName();
//创建解压文件
File entryFile = new File(entryFilePath);
if (entryFile.exists()){
//检测文件是否允许删除,如果不允许删除,将会抛出SecurityException
//SecurityManager securityManager = new SecurityManager();
//securityManager.checkDelete(entryFilePath);
//删除已存在的目标文件
entryFile.delete();
}
//写入文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(entryFile));
BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry));
while ((count = bis.read(buffer, 0, bufferSize)) != -1){
bos.write(buffer, 0, count);
}
//关闭
if(null != bis) bis.close();
if(null != bos){
bos.flush();
bos.close();
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new TzException("解压失败", e);
} finally {
if(zip != null){
try {
zip.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 根据原始rar路径,解压到指定文件夹下. winrar5.0以上版本压缩文件解压异常
* @param srcRarPath 原始rar路径
* @param dstDirectoryPath 解压到的文件夹
* @throws TzException
*/
public static void unRar(String srcRarPath, String dstDirectoryPath)
throws TzException {
if (StringUtils.isEmpty(srcRarPath)
|| StringUtils.isEmpty(dstDirectoryPath)){
throw new TzException("参数错误");
}
File zipFile = new File(srcRarPath);
if (!zipFile.exists()) {
throw new TzException(zipFile.getPath() + "所指文件不存在");
}
if (srcRarPath.toLowerCase().endsWith(".zip")) {
unZip(srcRarPath, dstDirectoryPath);
}else {
if (!srcRarPath.toLowerCase().endsWith(".rar")) {
throw new TzException("文件不是rar压缩文件");
}
File dstDiretory = new File(dstDirectoryPath);
if (!dstDiretory.exists()) {// 目标目录不存在时,创建该文件夹
dstDiretory.mkdirs();
}
Archive a = null;
FileOutputStream os = null;
try {
NativeStorage nsFile = new NativeStorage(new File(srcRarPath));
a = new Archive(nsFile);
if (a != null) {
a.getMainHeader().print(); // 打印文件信息.
FileHeader fh = a.nextFileHeader();
while (fh != null) {
String fileName= fh.getFileNameW().trim();
if(!existZH(fileName)){
fileName = fh.getFileNameString().trim();
}
if (fh.isDirectory()) { // 文件夹
File fol = new File(dstDirectoryPath + File.separator + fileName);
fol.mkdirs();
} else { // 文件
File out = new File(dstDirectoryPath + File.separator + fileName.trim());
try {// 之所以这么写try,是因为万一这里面有了异常,不影响继续解压.
if (!out.exists()) {
if (!out.getParentFile().exists()) {// 相对路径可能多级,可能需要创建父目录.
out.getParentFile().mkdirs();
}
out.createNewFile();
}
os = new FileOutputStream(out);
a.extractFile(fh, os);
os.close();
os = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
fh = a.nextFileHeader();
}
a.close();
a = null;
}
}catch(RarException e) {
e.printStackTrace();
throw new TzException("程序不支持该压缩格式,请将文件压缩成rar4或zip格式", e);
}catch(Exception e){
e.printStackTrace();
throw new TzException("解压失败", e);
}finally{
if(os!=null){
try{
os.close();
os=null;
}catch(Exception e){
e.printStackTrace();
}
}
if(a!=null){
try{
a.close();
a=null;
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
/**
* 删除单个文件
* @param fileName 要删除的文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删除单个文件" + fileName + "成功!");
return true;
} else {
System.out.println("删除单个文件" + fileName + "失败!");
return false;
}
} else {
System.out.println("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
/**
* 删除目录及目录下的文件
* @param dir 要删除的目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String dir) {
// 如果dir不以文件分隔符结尾,自动添加文件分隔符
if (!dir.endsWith(File.separator))
dir = dir + File.separator;
File dirFile = new File(dir);
// 如果dir对应的文件不存在,或者不是一个目录,则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
System.out.println("删除目录失败:" + dir + "不存在!");
return false;
}
boolean flag = true;
// 删除文件夹中的所有文件包括子目录
File[] files = dirFile.listFiles();
for (int i = 0; i < files.length; i++) {
// 删除子文件
if (files[i].isFile()) {
flag = ZipUtil.deleteFile(files[i].getAbsolutePath());
if (!flag) break;
}
// 删除子目录
else if (files[i].isDirectory()) {
flag = ZipUtil.deleteDirectory(files[i].getAbsolutePath());
if (!flag) break;
}
}
if (!flag) {
System.out.println("删除目录失败!");
return false;
}
// 删除当前目录
if (dirFile.delete()) {
System.out.println("删除目录" + dir + "成功!");
return true;
} else {
return false;
}
}
//判断是否包含中文
private static boolean existZH(String str) {
String regEx = "[\\u4e00-\\u9fa5]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
while (m.find()) {
return true;
}
return false;
}
//生成随机文件名,与文件上传命名一致
public static String getNowTime() {
Calendar cal = Calendar.getInstance();
int year = cal.get(1);
int month = cal.get(2) + 1;
int day = cal.get(5);
int hour = cal.get(10);
int minute = cal.get(12);
int second = cal.get(13);
int mi = cal.get(14);
long num = cal.getTimeInMillis();
int rand = (int) (Math.random() * 899999 + 100000);
return (new StringBuilder()).append(year).append(month).append(day).append(hour).append(minute).append(second)
.append(mi).append(num).append("_").append(rand).toString();
}
/* sFile:原文件地址,tFile目标文件地址 */
public static void copyFile(String sFile, String tFile) {
// System.out.println("原文件地址"+sFile+"目标"+tFile);
FileInputStream fi = null;
FileOutputStream fo = null;
FileChannel in = null;
FileChannel out = null;
File s = new File(sFile);
File t = new File(tFile);
if (s.exists() && s.isFile()) {
// System.out.println("是文件");
try {
fi = new FileInputStream(s);
fo = new FileOutputStream(t);
in = fi.getChannel();// 得到对应的文件通道
out = fo.getChannel();// 得到对应的文件通道
in.transferTo(0, in.size(), out);// 连接两个通道,并且从in通道读取,然后写入out通道
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fi.close();
in.close();
fo.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void copyFile2(String sFile, String tFile) {
File srcFile = new File(sFile);
if(srcFile.exists()){
File destFile = new File(tFile);
try {
FileUtils.copyFile(srcFile, destFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}