最近由于客户来回修改需求,使得我对代码也是反复修改,最终折腾完毕后,让我总结了3种Java生成的zip包。
1.普通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);}}}
压缩前的目标文件如下:
压缩后输出的文件以及解压后:
2.压缩后的压缩包解压即是文件,不需要文件夹,就是上面的案例,解压后还有一个packs文件夹,这里跳过,解压出来就是文件列表:
大体步骤相似,打包时代码需要调整,先上全部的代码:
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);}}}
这里主要是有第二个compress方法来处理:
由于文件夹结构如下:
这个方法在打包时,将外层的文件夹去掉,只保留内部文件夹
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包解压后,直接出现文件,没有最外层文件夹:
3.压缩时给zip包添加密码:
打出一个带解压密码的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方法工具中的方法:
/*** 使用给定密码压缩指定文件或文件夹到指定位置.* <p>* 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(P_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<File> temp = new ArrayList<File>();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<File> temp = new ArrayList<File>();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.密码最好使用动态生成的密码,来提高安全性。
压缩的方法很多,工作之余匆匆记录,肯定有不是很合理很全面的地方,有大佬看到欢迎指点。
如果觉得《使用Java压缩文件生成各种zip包总结(整理为工具类版)》对你有帮助,请点赞、收藏,并留下你的观点哦!