最近由于客户来回修改需求,使得我对代码也是反复修改,最终折腾完毕后,让我总结了3种Java生成的zip包。
过程如下:
打包E盘下packs文件夹中的内容,生成的zip包输出到E盘下,名称为packs.zip
具体代码实现过程注释即可。
import java.nio.file.Paths;
//compress方法需要传入2个参数,是两个地址
//第一个地址是目标打包文件的地址,第二个是zip包输出的地址
public static void main(String[] args) throws IOException {
String hallFilePath = "E:/" + "packs";
compress(Paths.get(hallFilePath).toString(), hallFilePath + ".zip");
}
//由此开始是所有相关的工具方法
public static void compress(String fromPath, String toPath) throws IOException {
File fromFile = new File(fromPath);
File toFile = new File(toPath);
if (!fromFile.exists()) {
throw new ServiceException(fromPath + "不存在!");
}
try (FileOutputStream outputStream = new FileOutputStream(toFile); CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32()); ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream)) {
String baseDir = "";
compress(fromFile, zipOutputStream, baseDir);
}
}
private static void compress(File file, ZipOutputStream zipOut, String baseDir) throws IOException {
if (file.isDirectory()) {
compressDirectory(file, zipOut, baseDir);
} else {
compressFile(file, zipOut, baseDir);
}
}
private static void compressFile(File file, ZipOutputStream zipOut, String baseDir) throws IOException {
if (!file.exists()) {
return;
}
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
ZipEntry entry = new ZipEntry(baseDir + file.getName());
zipOut.putNextEntry(entry);
int count;
byte[] data = new byte[BUFFER];
while ((count = bis.read(data, 0, BUFFER)) != -1) {
zipOut.write(data, 0, count);
}
}
}
private static void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) throws IOException {
File[] files = dir.listFiles();
if (files != null && ArrayUtils.isNotEmpty(files)) {
for (File file : files) {
compress(file, zipOut, baseDir + dir.getName() + File.separator);
}
}
}
大体步骤相似,打包时代码需要调整,先上全部的代码:
public static void main(String[] args) throws IOException {
String hallFilePath = "E:/" + "packs";
compress(Paths.get(hallFilePath).toString(), hallFilePath + ".zip");
}
public static void compress(String fromPath, String toPath) throws IOException {
File fromFile = new File(fromPath);
File toFile = new File(toPath);
if (!fromFile.exists()) {
throw new ServiceException(fromPath + "不存在!");
}
try (FileOutputStream outputStream = new FileOutputStream(toFile); CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32()); ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream)) {
String baseDir = "";
compress(fromFile, zipOutputStream, baseDir);
}
}
private static void compress(File file, ZipOutputStream zipOut, String baseDir) throws IOException {
if (file.isDirectory()) {
compressDirectory(file, zipOut, baseDir);
} else {
if (baseDir.equals("packs" + File.separator)) {
baseDir = File.separator;
} else if (baseDir.equals("packs" + File.separator + "examineeInfo" + File.separator)) {
baseDir = "examineeInfo" + File.separator;
}
compressFile(file, zipOut, baseDir);
}
}
private static void compressFile(File file, ZipOutputStream zipOut, String baseDir) throws IOException {
if (!file.exists()) {
return;
}
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
ZipEntry entry = new ZipEntry(baseDir + file.getName());
zipOut.putNextEntry(entry);
int count;
byte[] data = new byte[BUFFER];
while ((count = bis.read(data, 0, BUFFER)) != -1) {
zipOut.write(data, 0, count);
}
}
}
private static void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) throws IOException {
File[] files = dir.listFiles();
if (files != null && ArrayUtils.isNotEmpty(files)) {
for (File file : files) {
compress(file, zipOut, baseDir + dir.getName() + File.separator);
}
}
}
由于文件夹结构如下:
这个方法在打包时,将外层的文件夹去掉,只保留内部文件夹
private static void compress(File file, ZipOutputStream zipOut, String baseDir) throws IOException {
if (file.isDirectory()) {
compressDirectory(file, zipOut, baseDir);
} else {
//如果是文件夹,进来判断,是最外层packs文件夹还是内部的examineeInfo文件夹
//是最外层的则忽略掉,是内部的则把外层文件夹名称去掉
if (baseDir.equals("packs" + File.separator)) {
baseDir = File.separator;
} else if (baseDir.equals("packs" + File.separator + "examineeInfo" + File.separator)) {
baseDir = "examineeInfo" + File.separator;
}
compressFile(file, zipOut, baseDir);
}
}
这样压缩后的zip包解压后,直接出现文件,没有最外层文件夹:
程序运行示例截图:
示例代码:
public static void main(String[] args) {
//随机密码生成工具
String ownerPassword = PdfEncryptUtil.getCharAndNum(20);
//打包目标文件夹
String hallFilePath = "E:" + File.separator+ "packs";
//压缩包输出文件夹
String outPath = "E:" +File.separator+ "examineeInfo.zip";
//调用压缩方法zip进行压缩,参数含义下面介绍,返回的是压缩包的输出路径
String zipPath = zip(hallFilePath, outPath, false, "ceshi");
//打印出来
System.out.println(zipPath);
}
zip方法工具中的方法:
/**
* 使用给定密码压缩指定文件或文件夹到指定位置.
*
* dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者""
* 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;
* 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名.
*
* @param src 要压缩的文件或文件夹路径
* @param dest 压缩文件存放路径
* @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.
* 如果为false,将直接压缩目录下文件到压缩文件.
* @param passwd 压缩使用的密码
* @return 最终的压缩文件存放的绝对路径, 如果为null则说明压缩失败.
*/
public static String zip(String src, String dest, boolean isCreateDir, String passwd) {
File srcFile = new File(src);
dest = buildDestinationZipFilePath(srcFile, dest);
ZipParameters parameters = new ZipParameters();
// 压缩方式
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
// 压缩级别
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
if (!StringUtils.isEmpty(passwd)) {
parameters.setEncryptFiles(true);
// 加密方式
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
parameters.setPassword(passwd.toCharArray());
}
try {
ZipFile zipFile = new ZipFile(dest);
if (srcFile.isDirectory()) {
// 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构
if (!isCreateDir) {
File[] subFiles = srcFile.listFiles();
for (int i = 0; i < subFiles.length; i++) {
if (subFiles[i].isDirectory()) {
zipFile.addFolder(subFiles[i], parameters);
} else {
ArrayList temp = new ArrayList();
Collections.addAll(temp, subFiles[i]);
zipFile.addFiles(temp, parameters);
}
}
return dest;
}
zipFile.addFolder(srcFile, parameters);
} else {
zipFile.addFile(srcFile, parameters);
}
return dest;
} catch (ZipException e) {
e.printStackTrace();
}
return null;
}
private static String buildDestinationZipFilePath(File srcFile, String destParam) {
if (StringUtils.isEmpty(destParam)) {
if (srcFile.isDirectory()) {
destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip";
} else {
String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
destParam = srcFile.getParent() + File.separator + fileName + ".zip";
}
} else {
// 在指定路径不存在的情况下将其创建出来
createDestDirectoryIfNecessary(destParam);
if (destParam.endsWith(File.separator)) {
String fileName = "";
if (srcFile.isDirectory()) {
fileName = srcFile.getName();
} else {
fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
}
destParam += fileName + ".zip";
}
}
return destParam;
}
private static void createDestDirectoryIfNecessary(String destParam) {
File destDir = null;
if (destParam.endsWith(File.separator)) {
destDir = new File(destParam);
} else {
destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator)));
}
if (!destDir.exists()) {
destDir.mkdirs();
}
}
这里打包出来的加密zip包也是解压开就是文件列表的格式,没有最外层文件夹包裹,如果想要最外层文件夹包裹,只需要改动下zip方法的try块中的if...else语句即可:
try {
ZipFile zipFile = new ZipFile(dest);
if (srcFile.isDirectory()) {
// 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构
if (!isCreateDir) {
File[] subFiles = srcFile.listFiles();
ArrayList temp = new ArrayList();
Collections.addAll(temp, subFiles);
zipFile.addFiles(temp, parameters);
return dest;
}
zipFile.addFolder(srcFile, parameters);
} else {
zipFile.addFile(srcFile, parameters);
}
return dest;
} catch (ZipException e) {
e.printStackTrace();
}
生成效果:
1.zip包输出地址在定义时,一定要以.zip结尾,否则会出错。
2.代表文件夹层级关系的/在有的方法中,或者linux服务器上不识别,最好使用File.separator来表示层级,上面我也有用到过。
3.密码最好使用动态生成的密码,来提高安全性。
压缩的方法很多,工作之余匆匆记录,肯定有不是很合理很全面的地方,有大佬看到欢迎指点。