zip文件的解压,涉及到解压前、解压后的大小、数量校验。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* zip处理工具类
*
* @author guohao
* @since 2020-10-27
*/
public class ZipUtil {
private static final String DEFAULT_CHARSET = "gbk";
private static final int INIT_BUFFER_SIZE = 1024;
private static final int MAX_DECOMPRESS_SIZE = 12 * 1024 * 1024;
private static final String MAX_DECOMPRESS_SIZE_STR = MAX_DECOMPRESS_SIZE / (1024 * 1024) + "MB";
private ZipUtil() {
}
/**
* 从zip的inputStream中读出 键为文件名,值为内容
*
* @param zipName 文件名称
* @param inputStream zip文件流
* @param serviceMaxSize 服务最大数量
* @param serviceNumInDb 数据库中的当前的服务数量
* @return 文件名,内容
* @throws ServiceException 服务异常
*/
public static Map<String, String> readZipByInputStream(String zipName, InputStream inputStream, long serviceMaxSize,
long serviceNumInDb) throws ServiceException {
Map<String, String> results = new HashMap<>();
try (ZipInputStream zip = new ZipInputStream(inputStream, Charset.forName(DEFAULT_CHARSET))) {
ZipEntry zipEntry;
long decompressSize = 0;
while ((zipEntry = zip.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
continue;
}
String fileName = new String(zipEntry.getName().getBytes(), StandardCharsets.UTF_8);
LOGGER.info("Start to parse BPMN file({}) content in zip file({}).", fileName, zipName);
byte[] bytes = readPerEntry(zip);
decompressSize += bytes.length;
checkUnzipTotalSize(zipName, decompressSize);
String content = new String(bytes, StandardCharsets.UTF_8);
results.put(fileName, content);
}
} catch (IOException e) {
throw new ServiceExtendException(ServiceErrorCode.OPERATION_FAILED, "The zip file stream parsing failed.",
e);
}
long maxEntriesSize = serviceMaxSize - serviceNumInDb;
checkUnzipFileNum(serviceNumInDb, results, maxEntriesSize);
return results;
}
private static void checkUnzipFileNum(long serviceNumInDb, Map<String, String> results, long maxEntriesSize)
throws ServiceExtendException {
if (results.size() > maxEntriesSize) {
LOGGER.error("Uncompress result num is too many than max size({}).", maxEntriesSize);
throw new ServiceExtendException(ErrorCode.IMPORT_SERVICE_NUM_TOOT_LARGE, new String[] {
String.valueOf(serviceNumInDb), String.valueOf(maxEntriesSize), String.valueOf(results.size())
});
}
}
private static void checkUnzipTotalSize(String zipName, long decompressSize) throws ServiceExtendException {
if (decompressSize > MAX_DECOMPRESS_SIZE) {
LOGGER.error("Uncompress result size ({}) more than max size({}).", decompressSize,
MAX_DECOMPRESS_SIZE);
throw new ServiceExtendException(ErrorCode.DECOMPRESSED_TOO_LARGE,
new String[] {zipName, MAX_DECOMPRESS_SIZE_STR});
}
}
private static byte[] readPerEntry(ZipInputStream zip) throws ServiceException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
int num = -1;
byte[] temps = new byte[INIT_BUFFER_SIZE];
while ((num = zip.read(temps, 0, temps.length)) > -1) {
byteArrayOutputStream.write(temps, 0, num);
}
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new ServiceExtendException(ServiceErrorCode.ERR_PARAM, "The zip file stream parsing failed.", e);
}
}
}