
net.apexes.commons.lang.Zips Maven / Gradle / Ivy
/*
* Copyright (c) 2018, apexes.net. All rights reserved.
*
* http://www.apexes.net
*
*/
package net.apexes.commons.lang;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
*
* @author HeDYn
*/
public final class Zips {
/**
* 将指定的zip文件中的内容(不含zip文件名目录)解压缩到descDir目录中
* @param zipFile 要解压缩的zip文件
* @param descDir zip文件中的内容要解压缩到的目标目录
*/
public static void unzip(Path zipFile, Path descDir) throws Exception {
unzip(zipFile, descDir, false);
}
public static void unzipSafeOverwrite(Path zipFile, Path descDir) throws Exception {
unzip(zipFile, descDir, true);
}
/**
* 将指定的zip文件中的内容(不含zip文件名目录)解压缩到descDir目录中
* @param zipFile 要解压缩的zip文件
* @param descDir zip文件中的内容要解压缩到的目标目录
* @param safeOverwrite 为true时,如果目标文件存在将采用先解压缩到 .temp 文件,再重命名为目标文件的方式
*/
public static void unzip(Path zipFile, Path descDir, boolean safeOverwrite) throws Exception {
if (Files.notExists(descDir)) {
Files.createDirectory(descDir);
}
byte[] buf = new byte[Streams.BUFFER_SIZE];
try (ZipFile zip = new ZipFile(zipFile.toFile())) {
Enumeration extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String zipEntryName = entry.getName();
Path destFile = descDir.resolve(zipEntryName);
if (entry.isDirectory()) {
Files.createDirectories(destFile);
} else {
Path destFileParentDir = destFile.getParent();
// 判断路径是否存在, 不存在则创建文件路径
if (Files.notExists(destFileParentDir)) {
Files.createDirectories(destFileParentDir);
}
if (safeOverwrite) {
Path tempDestFile = descDir.resolve(zipEntryName + ".temp");
try (InputStream is = zip.getInputStream(entry)) {
try (OutputStream os = Files.newOutputStream(tempDestFile)) {
int len;
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
}
}
try {
Files.move(tempDestFile, destFile, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
Files.delete(tempDestFile);
throw e;
}
} else {
try (InputStream is = zip.getInputStream(entry)) {
try (OutputStream os = Files.newOutputStream(destFile)) {
int len;
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
}
}
}
}
}
}
}
public static ZipCompress keepStructure() {
return new ZipCompressImpl(true);
}
public static ZipCompress notStructure() {
return new ZipCompressImpl(true);
}
/**
* @author HeDYn
*/
public interface ZipCompress {
ZipCompress snapshoot();
ZipCompress level(int level);
ZipCompress bestSpeed();
ZipCompress bestCompression();
ZipCompress addFile(String name, File file);
ZipCompress addFile(File... files);
ZipCompress addFiles(List files);
boolean isEmpty();
void compress(OutputStream out) throws Exception;
}
/**
* @author HeDYn
*/
private static class ZipCompressImpl implements ZipCompress {
private final boolean keepStructure;
private final Map fileMap;
private boolean snapshoot;
private Integer level;
private ZipCompressImpl(boolean keepStructure) {
this.keepStructure = keepStructure;
this.fileMap = new LinkedHashMap<>();
}
@Override
public ZipCompress snapshoot() {
this.snapshoot = true;
return this;
}
@Override
public ZipCompress level(int level) {
if (level < 0 || level > 9) {
throw new IllegalArgumentException("invalid compression level");
}
this.level = level;
return this;
}
@Override
public ZipCompress bestSpeed() {
this.level = Deflater.BEST_SPEED;
return this;
}
@Override
public ZipCompress bestCompression() {
this.level = Deflater.BEST_COMPRESSION;
return this;
}
@Override
public ZipCompress addFile(String name, File file) {
if (file.exists()) {
fileMap.put(file, name);
}
return this;
}
@Override
public ZipCompress addFile(File... files) {
Checks.verifyNotEmpty(files, "files");
return addFiles(Arrays.asList(files));
}
@Override
public ZipCompress addFiles(List files) {
Checks.verifyNotEmpty(files, "files");
for (File file : files) {
if (file.exists()) {
fileMap.put(file, file.getName());
}
}
return this;
}
@Override
public boolean isEmpty() {
return fileMap.isEmpty();
}
@Override
public void compress(OutputStream out) throws Exception {
try (ZipOutputStream zos = new ZipOutputStream(out)) {
if (level != null) {
zos.setLevel(level);
}
for (Map.Entry entry : fileMap.entrySet()) {
doCompress(entry.getKey(), zos, entry.getValue(), keepStructure, snapshoot);
}
zos.finish();
}
}
private static void doCompress(File sourceFile,
ZipOutputStream zos,
String name,
boolean keepStructure,
boolean snapshoot) throws Exception {
if (sourceFile.isFile()) {
zos.putNextEntry(new ZipEntry(name));
Streams.transfer(sourceFile, zos, snapshoot);
zos.closeEntry();
} else if (sourceFile.isDirectory()) {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
// 需要保留原来文件结构时,需要对空文件夹进行处理
if (keepStructure) {
zos.putNextEntry(new ZipEntry(name + "/"));
zos.closeEntry();
}
} else {
for (File file : listFiles) {
if (keepStructure) {
// 保留原来文件结构时前面需要带上父文件夹名字
doCompress(file, zos, name + "/" + file.getName(), keepStructure, snapshoot);
} else {
doCompress(file, zos, file.getName(), keepStructure, snapshoot);
}
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy