自己封装的工具类之【java压缩、解压工具】

ゞ 浴缸里的玫瑰 2022-01-30 01:37 370阅读 0赞

越发觉得自己封装的工具类很好用,还是贴出来分享一下:

  1. package com.fulong.utils.v2.tool;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileOutputStream;
  7. import java.nio.charset.Charset;
  8. import java.nio.file.Path;
  9. import java.nio.file.Paths;
  10. import java.util.Enumeration;
  11. import java.util.zip.CRC32;
  12. import java.util.zip.CheckedOutputStream;
  13. import java.util.zip.ZipEntry;
  14. import java.util.zip.ZipFile;
  15. import java.util.zip.ZipOutputStream;
  16. import org.apache.commons.lang.StringUtils;
  17. import com.fulong.utils.v2.tool.file.FileUtil;
  18. public class ZipUtil {
  19. /**
  20. * 递归压缩文件夹
  21. *
  22. * @param file
  23. * 当前待压缩的文件或目录对象;
  24. * @param zos
  25. * 输出--压缩文件存储对象
  26. * @throws Exception
  27. */
  28. private static void zip(File file, ZipOutputStream zipOut, String prefix) throws Exception {
  29. if (file == null) {
  30. return;
  31. }
  32. // 如果是文件,则直接压缩该文件
  33. if (file.isFile()) {
  34. int count, bufferLen = 1024;
  35. byte data[] = new byte[bufferLen];
  36. // 获取文件相对于压缩文件夹根目录的子路径
  37. ZipEntry entry = new ZipEntry(prefix + file.getName());
  38. zipOut.putNextEntry(entry);
  39. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
  40. while ((count = bis.read(data, 0, bufferLen)) != -1) {
  41. zipOut.write(data, 0, count);
  42. }
  43. bis.close();
  44. zipOut.closeEntry();
  45. }
  46. // 空目录
  47. else if (file.listFiles() == null || file.listFiles().length <= 0) {
  48. ZipEntry zipEntry = new ZipEntry(prefix + file.getName() + File.separator);
  49. zipOut.putNextEntry(zipEntry);
  50. zipOut.closeEntry();
  51. }
  52. // 如果是目录,则压缩整个目录
  53. else {
  54. File[] childFileList = file.listFiles();
  55. prefix += file.getName() + File.separator;
  56. for (int n = 0; n < childFileList.length; n++) {
  57. // File f = childFileList[n];
  58. zip(childFileList[n], zipOut, prefix);
  59. }
  60. }
  61. }
  62. /**
  63. * 对文件或文件目录进行压缩
  64. *
  65. * @param srcPath
  66. * 要压缩的源文件路径。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径
  67. * @param zipPath
  68. * 压缩文件保存的路径。注意:zipPath不能是srcPath路径下的子文件夹
  69. * @param zipFileName
  70. * 要压缩的文件名
  71. * @return File 压缩后的文件
  72. * @throws Exception
  73. */
  74. public static File zip(Path srcPath, Path zipPath, String zipFileName) throws Exception {
  75. if (StringUtils.isEmpty(zipFileName)) {
  76. zipFileName = "temp.zip";
  77. }
  78. CheckedOutputStream cos = null;
  79. ZipOutputStream zos = null;
  80. try {
  81. File srcFile = srcPath.toFile();
  82. // 判断压缩文件保存的路径是否为源文件路径的子文件夹,如果是,则抛出异常(防止无限递归压缩的发生)
  83. if (srcFile.isDirectory() && zipPath.toString().indexOf(srcPath.toString()) != -1) {
  84. throw new Exception("zipPath must not be the child directory of srcPath.");
  85. }
  86. // 判断压缩文件保存的路径是否存在,如果不存在,则创建目录
  87. File zipDir = zipPath.toFile();
  88. if (!zipDir.exists() || !zipDir.isDirectory()) {
  89. zipDir.mkdirs();
  90. }
  91. // 创建压缩文件保存的文件对象
  92. Path zipFilePath = zipPath.resolve(zipFileName);
  93. File zipFile = zipFilePath.toFile();
  94. if (zipFile.exists()) {
  95. // 检测文件是否允许删除,如果不允许删除,将会抛出SecurityException
  96. // SecurityManager securityManager = new SecurityManager();
  97. // securityManager.checkDelete(zipFilePath.toString());
  98. // 删除已存在的目标文件
  99. zipFile.delete();
  100. }
  101. cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());
  102. zos = new ZipOutputStream(cos);
  103. // 调用递归压缩方法进行目录或文件压缩
  104. zip(srcPath.toFile(), zos, "");
  105. zos.flush();
  106. zos.close();
  107. return zipFile;
  108. } catch (Exception e) {
  109. throw e;
  110. } finally {
  111. try {
  112. if (zos != null) {
  113. zos.close();
  114. }
  115. } catch (Exception e) {
  116. e.printStackTrace();
  117. }
  118. }
  119. }
  120. /**
  121. * 解压缩zip包
  122. * 只能实现当前zip包解压,无法递归解压
  123. * @param zipFile
  124. * zip文件的全路径
  125. * @param unzipFilePath
  126. * 解压后的文件保存的路径
  127. * @param includeZipFileName
  128. * 解压后的文件保存的路径是否包含压缩文件的文件名。true-包含;false-不包含
  129. * @return Path 返回不是只有一个目录作为孩子的最深层的目录
  130. */
  131. @SuppressWarnings("unchecked")
  132. public static Path unzip(File zipFile, Path unzipFilePath, boolean includeZipFileName) throws Exception {
  133. // 如果解压后的文件保存路径包含压缩文件的文件名,则追加该文件名到解压路径
  134. if (includeZipFileName) {
  135. String fileName = zipFile.getName();
  136. if (StringUtils.isNotEmpty(fileName)) {
  137. fileName = fileName.substring(0, fileName.lastIndexOf("."));
  138. }
  139. unzipFilePath = unzipFilePath.resolve(fileName);
  140. }
  141. // 创建解压缩文件保存的路径
  142. File unzipFileDir = unzipFilePath.toFile();
  143. if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()) {
  144. unzipFileDir.mkdirs();
  145. }
  146. // 开始解压
  147. int count = 0;
  148. int bufferSize = 1024;
  149. byte[] buffer = new byte[bufferSize];
  150. // ZipFile zip = new ZipFile(zipFile,Charset.forName("UTF-8"));
  151. /*
  152. * 获取操作系统的默认字符编码
  153. */
  154. String charSet4OS = System.getProperty("sun.jnu.encoding");
  155. ZipFile zip = new ZipFile(zipFile,Charset.forName(charSet4OS));
  156. Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zip.entries();
  157. // 循环对压缩包里的每一个文件进行解压
  158. while (entries.hasMoreElements()) {
  159. ZipEntry entry = entries.nextElement();
  160. // 构建压缩包中一个文件解压后保存的文件全路径
  161. Path entryFilePath = unzipFilePath.resolve(entry.getName());
  162. // 创建解压文件
  163. File entryFile = entryFilePath.toFile();
  164. /**
  165. * 看了entry.isDirectory()为endsWith("/")来判断目录
  166. */
  167. if(entry.isDirectory()||entry.getName().endsWith(File.separator)){//是目录,必须使用ZipEntry,使用File无法判断
  168. if(entryFile.exists()){
  169. entryFile.delete();
  170. }
  171. entryFile.mkdirs();
  172. continue;
  173. }
  174. if(!entryFile.getParentFile().exists()){
  175. entryFile.getParentFile().mkdirs();
  176. }
  177. if (entryFile.exists()) {
  178. // 删除已存在的目标文件
  179. entryFile.delete();
  180. }
  181. // 写入文件
  182. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(entryFile));
  183. BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry));
  184. while ((count = bis.read(buffer, 0, bufferSize)) != -1) {
  185. bos.write(buffer, 0, count);
  186. }
  187. bos.flush();
  188. bos.close();
  189. bis.close();
  190. }
  191. zip.close();
  192. return FileUtil.farthestAloneDirFrom(unzipFilePath);
  193. }
  194. public static void main(String[] args) {
  195. Path zipPath = Paths.get("d:/a");
  196. Path dir = Paths.get("d:/b");
  197. String zipFileName = "test.zip";
  198. try {
  199. zip(zipPath, dir, zipFileName);
  200. } catch (Exception e) {
  201. e.printStackTrace();
  202. }
  203. File zipFile = dir.resolve(zipFileName).toFile();
  204. Path unzipFilePath = Paths.get("d:/c");
  205. try {
  206. unzip(zipFile, unzipFilePath, false);
  207. } catch (Exception e) {
  208. e.printStackTrace();
  209. }
  210. }
  211. }

涉及FileUtil.farthestAloneDirFrom()方法,单独贴出来:

  1. /**
  2. * @note 存储离unzipFilePath最远的唯一单独文件夹
  3. * @return 返回 “不能只有一个目录作为孩子的最深层的目录 ” 如果srcPath 是空文件夹 返回srcPath 如果srcPath
  4. * 不是目录,返回srcPath的上层目录
  5. */
  6. public static Path farthestAloneDirFrom(Path srcPath) {
  7. if (srcPath == null) {
  8. return null;
  9. }
  10. File farthestAloneDir = srcPath.toFile();
  11. if (!farthestAloneDir.isDirectory()) {
  12. return srcPath.getParent();
  13. }
  14. if (farthestAloneDir.listFiles() == null || farthestAloneDir.listFiles().length <= 0
  15. || farthestAloneDir.listFiles().length > 1) {
  16. return srcPath;
  17. }
  18. /*
  19. * 里面只有单独一个文件
  20. */
  21. File oneFile = farthestAloneDir.listFiles()[0];
  22. return farthestAloneDirFrom(srcPath.resolve(oneFile.toPath()));
  23. }

使用时注意,在压缩时,压缩的目录不能是压缩后文件的所在目录,因为这会陷入无限压缩的死循环,如果非要放在次目录,可以中间用一个临时目录过渡下,然后移动过去就行了。

jdk8的Files有很多文件操作的方法,很好用:

Files.move();Files.copy();

发表评论

表情:
评论列表 (有 0 条评论,370人围观)

还没有评论,来说两句吧...

相关阅读