Commit 43a803b033531692671d15bac6db3ed77fa0e194
Merge branch 'dev2.0' into 'master'
feat #增加自定义文件操作工具 增加自定义文件操作工具 See merge request !1
Showing
2 changed files
with
388 additions
and
5 deletions
pom.xml
| @@ -16,20 +16,27 @@ | @@ -16,20 +16,27 @@ | ||
| 16 | <lombok.version>1.18.10</lombok.version> | 16 | <lombok.version>1.18.10</lombok.version> |
| 17 | <commons-codec.version>1.11</commons-codec.version> | 17 | <commons-codec.version>1.11</commons-codec.version> |
| 18 | <guava.vsersion>28.1-jre</guava.vsersion> | 18 | <guava.vsersion>28.1-jre</guava.vsersion> |
| 19 | - <slf4j.version>1.7.24</slf4j.version> | 19 | + <slf4j.version>1.7.25</slf4j.version> |
| 20 | <fastjson.version>1.2.49</fastjson.version> | 20 | <fastjson.version>1.2.49</fastjson.version> |
| 21 | <spring-web.version>5.0.9.RELEASE</spring-web.version> | 21 | <spring-web.version>5.0.9.RELEASE</spring-web.version> |
| 22 | <spring-security-core.version>5.0.9.RELEASE</spring-security-core.version> | 22 | <spring-security-core.version>5.0.9.RELEASE</spring-security-core.version> |
| 23 | <ehcache.version>2.6.11</ehcache.version> | 23 | <ehcache.version>2.6.11</ehcache.version> |
| 24 | + <commons-io.version>2.7</commons-io.version> | ||
| 24 | </properties> | 25 | </properties> |
| 25 | 26 | ||
| 26 | 27 | ||
| 27 | <dependencies> | 28 | <dependencies> |
| 29 | +<!-- <dependency>--> | ||
| 30 | +<!-- <groupId>org.slf4j</groupId>--> | ||
| 31 | +<!-- <artifactId>slf4j-api</artifactId>--> | ||
| 32 | +<!-- <version>${slf4j.version}</version>--> | ||
| 33 | +<!-- <scope>provided</scope>--> | ||
| 34 | +<!-- </dependency>--> | ||
| 35 | + <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> | ||
| 28 | <dependency> | 36 | <dependency> |
| 29 | - <groupId>org.slf4j</groupId> | ||
| 30 | - <artifactId>slf4j-api</artifactId> | ||
| 31 | - <version>${slf4j.version}</version> | ||
| 32 | - <scope>provided</scope> | 37 | + <groupId>commons-io</groupId> |
| 38 | + <artifactId>commons-io</artifactId> | ||
| 39 | + <version>${commons-io.version}</version> | ||
| 33 | </dependency> | 40 | </dependency> |
| 34 | <dependency> | 41 | <dependency> |
| 35 | <groupId>com.google.guava</groupId> | 42 | <groupId>com.google.guava</groupId> |
src/main/java/com/irrigation/icl/utils/LocalFileUtils.java
0 → 100644
| 1 | +package com.irrigation.icl.utils; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.irrigation.icl.exception.ContextRuntimeException; | ||
| 5 | +import lombok.extern.slf4j.Slf4j; | ||
| 6 | +import org.apache.commons.io.FileUtils; | ||
| 7 | +import org.springframework.util.Assert; | ||
| 8 | +import org.springframework.util.StringUtils; | ||
| 9 | +import org.springframework.web.multipart.MultipartFile; | ||
| 10 | + | ||
| 11 | +import java.io.*; | ||
| 12 | +import java.nio.charset.Charset; | ||
| 13 | +import java.util.Arrays; | ||
| 14 | +import java.util.Enumeration; | ||
| 15 | +import java.util.List; | ||
| 16 | +import java.util.Optional; | ||
| 17 | +import java.util.zip.ZipEntry; | ||
| 18 | +import java.util.zip.ZipFile; | ||
| 19 | +import java.util.zip.ZipOutputStream; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * @description: | ||
| 23 | + * @Author: yangLang | ||
| 24 | + * @CreateDate: 2020/9/2 14:39 | ||
| 25 | + */ | ||
| 26 | +@Slf4j | ||
| 27 | +public class LocalFileUtils { | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 文件后缀分隔符 | ||
| 32 | + */ | ||
| 33 | + public static final String FILE_SUFFIX_SEPARATOR = "."; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 编码方式 | ||
| 37 | + */ | ||
| 38 | + public final static String DEFAULT_CHARSET = "GBK"; | ||
| 39 | + | ||
| 40 | + private LocalFileUtils() { | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 创建文件 | ||
| 45 | + * | ||
| 46 | + * @param parentFile 辅机目录 | ||
| 47 | + * @param fileName 文件名称 | ||
| 48 | + * @return java.io.File | ||
| 49 | + * @Author yangLang | ||
| 50 | + * @Date 15:30 2020/9/2 | ||
| 51 | + */ | ||
| 52 | + public static File getFile(File parentFile, String fileName) { | ||
| 53 | + Assert.notNull(fileName, "Depending create file is null"); | ||
| 54 | + File file; | ||
| 55 | + if (ObjectUtils.isNull(parentFile)) { | ||
| 56 | + file = new File(fileName); | ||
| 57 | + } else { | ||
| 58 | + file = new File(parentFile, fileName); | ||
| 59 | + } | ||
| 60 | + if (!file.exists()) { | ||
| 61 | + try { | ||
| 62 | + file.createNewFile(); | ||
| 63 | + } catch (IOException e) { | ||
| 64 | + log.error("Create File Failed:{}", e.getMessage()); | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + Assert.isTrue(file.exists(), "Create file failed"); | ||
| 68 | + return file; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 创建目录 | ||
| 73 | + * | ||
| 74 | + * @param parentFile 父目录 | ||
| 75 | + * @param filePath 目录的指定路径 | ||
| 76 | + * @return java.io.File | ||
| 77 | + * @Author yangLang | ||
| 78 | + * @Date 15:22 2020/9/2 | ||
| 79 | + */ | ||
| 80 | + public static File getDirectoryFile(File parentFile, String filePath) { | ||
| 81 | + Assert.notNull(filePath, "Depending created file is null"); | ||
| 82 | + File file; | ||
| 83 | + if (ObjectUtils.isNull(parentFile)) { | ||
| 84 | + file = new File(filePath); | ||
| 85 | + } else { | ||
| 86 | + file = new File(parentFile, filePath); | ||
| 87 | + } | ||
| 88 | + if (!file.exists()) { | ||
| 89 | + file.mkdirs(); | ||
| 90 | + } | ||
| 91 | + Assert.isTrue(file.exists(), "Created file failed"); | ||
| 92 | + return file; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * 获取文件的后缀名 | ||
| 97 | + * | ||
| 98 | + * @param file 文件名 | ||
| 99 | + * @param isContainSuffixSeparator 是否包含文件后缀分隔符 | ||
| 100 | + * @return java.lang.String | ||
| 101 | + * @Author yangLang | ||
| 102 | + * @Date 16:01 2020/9/2 | ||
| 103 | + */ | ||
| 104 | + public static String getFileExtension(File file, boolean isContainSuffixSeparator) { | ||
| 105 | + Assert.notNull(file, "File is null"); | ||
| 106 | + String fileName = file.getName(); | ||
| 107 | + Assert.notNull(fileName, "File is not exist"); | ||
| 108 | + int index = fileName.lastIndexOf(FILE_SUFFIX_SEPARATOR); | ||
| 109 | + if (index == -1 || index >= fileName.length()) { | ||
| 110 | + return null; | ||
| 111 | + } | ||
| 112 | + if (!isContainSuffixSeparator) { | ||
| 113 | + index++; | ||
| 114 | + } | ||
| 115 | + return fileName.substring(index); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * 获取文件的后缀名 | ||
| 120 | + * | ||
| 121 | + * @param filePath 文件路径 | ||
| 122 | + * @param isContainSuffixSeparator 是否包含文件后缀分隔符 | ||
| 123 | + * @return java.lang.String | ||
| 124 | + * @Author yangLang | ||
| 125 | + * @Date 16:02 2020/9/2 | ||
| 126 | + */ | ||
| 127 | + public static String getFilePathExtension(String filePath, boolean isContainSuffixSeparator) { | ||
| 128 | + Assert.notNull(filePath, "File is null"); | ||
| 129 | + int index = filePath.lastIndexOf(FILE_SUFFIX_SEPARATOR); | ||
| 130 | + if (index == -1 || index >= filePath.length()) { | ||
| 131 | + return null; | ||
| 132 | + } | ||
| 133 | + if (!isContainSuffixSeparator) { | ||
| 134 | + index++; | ||
| 135 | + } | ||
| 136 | + return filePath.substring(index); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + /** | ||
| 140 | + * 获取 MultipartFile 文件后缀 | ||
| 141 | + * | ||
| 142 | + * @param file 文件 | ||
| 143 | + * @param isContainSuffixSeparator 是否包含文件后缀分隔符 | ||
| 144 | + * @return java.lang.String 后缀字符串 | ||
| 145 | + * @Author yangLang | ||
| 146 | + * @Date 9:39 2020/9/3 | ||
| 147 | + */ | ||
| 148 | + public static String getMultipartFileExtension(MultipartFile file, boolean isContainSuffixSeparator) { | ||
| 149 | + Assert.notNull(file, "File is null"); | ||
| 150 | + int index = file.getOriginalFilename().lastIndexOf(FILE_SUFFIX_SEPARATOR); | ||
| 151 | + if (index == -1 || index >= file.getOriginalFilename().length()) { | ||
| 152 | + return null; | ||
| 153 | + } | ||
| 154 | + if (!isContainSuffixSeparator) { | ||
| 155 | + index++; | ||
| 156 | + } | ||
| 157 | + return file.getOriginalFilename().substring(index); | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + /** | ||
| 161 | + * 判断文件是否为期望的文件格式(不包含文件后缀分隔符) | ||
| 162 | + * | ||
| 163 | + * @param file 文件 | ||
| 164 | + * @param expectExtension 期望的文件格式 | ||
| 165 | + * @return boolean | ||
| 166 | + * @Author yangLang | ||
| 167 | + * @Date 16:17 2020/9/2 | ||
| 168 | + */ | ||
| 169 | + public static boolean judgeFileExtension(File file, String expectExtension) { | ||
| 170 | + Assert.notNull(file, "Depend judge file is null"); | ||
| 171 | + Assert.notNull(expectExtension, "The expect extension is null"); | ||
| 172 | + String fileExtension = getFileExtension(file, false); | ||
| 173 | + return expectExtension.equalsIgnoreCase(fileExtension); | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + /** | ||
| 177 | + * 判断文件路径是否为期望的文件格式(不包含文件后缀分隔符) | ||
| 178 | + * | ||
| 179 | + * @param filePath 文件路径 | ||
| 180 | + * @param expectExtension 期望的文件格式 | ||
| 181 | + * @return boolean | ||
| 182 | + * @Author yangLang | ||
| 183 | + * @Date 9:42 2020/9/3 | ||
| 184 | + */ | ||
| 185 | + public static boolean judgeFilePathExtension(String filePath, String expectExtension) { | ||
| 186 | + Assert.notNull(filePath, "Depend judge file is null"); | ||
| 187 | + Assert.notNull(expectExtension, "The expect extension is null"); | ||
| 188 | + String fileExtension = getFilePathExtension(filePath, false); | ||
| 189 | + return expectExtension.equalsIgnoreCase(fileExtension); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + /** | ||
| 193 | + * 判断文件是否为期望的文件格式(不包含文件后缀分隔符) | ||
| 194 | + * | ||
| 195 | + * @param file 文件 | ||
| 196 | + * @param expectExtension 期望的格式 | ||
| 197 | + * @return boolean | ||
| 198 | + * @Author yangLang | ||
| 199 | + * @Date 16:19 2020/9/2 | ||
| 200 | + */ | ||
| 201 | + public static boolean judgeMultipartFileExtension(MultipartFile file, String expectExtension) { | ||
| 202 | + Assert.notNull(file, "Depend judge file is null"); | ||
| 203 | + Assert.notNull(expectExtension, "The expect extension is null"); | ||
| 204 | + String fileExtension = getFilePathExtension(file.getOriginalFilename(), false); | ||
| 205 | + return expectExtension.equalsIgnoreCase(fileExtension); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + /** | ||
| 209 | + * multipartFile 转 File | ||
| 210 | + * | ||
| 211 | + * @param multipartFile 带转换的 multipartFile 文件 | ||
| 212 | + * @param parentFile 转换完成后的文件所在的目录 | ||
| 213 | + * @return java.io.File | ||
| 214 | + * @Author yangLang | ||
| 215 | + * @Date 17:03 2020/9/2 | ||
| 216 | + */ | ||
| 217 | + public static File multipartFile2File(MultipartFile multipartFile, File parentFile) { | ||
| 218 | + Assert.notNull(multipartFile, "Depend trances file is null"); | ||
| 219 | + Assert.isTrue(parentFile.isDirectory(), "Parent File not a directory"); | ||
| 220 | + File tempFile = getFile(parentFile, multipartFile.getOriginalFilename()); | ||
| 221 | + try (InputStream inputStream = multipartFile.getInputStream()) { | ||
| 222 | + FileUtils.copyInputStreamToFile(inputStream, tempFile); | ||
| 223 | + } catch (IOException e) { | ||
| 224 | + throw new ContextRuntimeException("文件转换失败"); | ||
| 225 | + } | ||
| 226 | + return tempFile; | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + /** | ||
| 230 | + * 解压文件到指定目录,解压后的文件名和之前一致 | ||
| 231 | + * | ||
| 232 | + * @param unZipFile 解压文件 | ||
| 233 | + * @param parentFile 解压文件后所置的目录 | ||
| 234 | + * @param encode 编码方式,默认是GBK | ||
| 235 | + * @param isDeleteZipFile 是否需要删除压缩文件,默认不删除 | ||
| 236 | + * @return void | ||
| 237 | + * @Author yangLang | ||
| 238 | + * @Date 17:14 2020/9/2 | ||
| 239 | + */ | ||
| 240 | + public static void unZipFile(File unZipFile, File parentFile, String encode, Boolean isDeleteZipFile) { | ||
| 241 | + Assert.notNull(parentFile, "Unzip file's parent file is null"); | ||
| 242 | + try (ZipFile zip = new ZipFile(unZipFile, Charset.forName(Optional.ofNullable(encode).orElse(DEFAULT_CHARSET)))) { | ||
| 243 | + FileOutputStream out = null; | ||
| 244 | + for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) { | ||
| 245 | + ZipEntry entry = entries.nextElement(); | ||
| 246 | + String zipEntryName = entry.getName(); | ||
| 247 | + try (InputStream in = zip.getInputStream(entry)) { | ||
| 248 | + int index = zipEntryName.lastIndexOf(StringUtils.cleanPath(File.separator)); | ||
| 249 | + File file; | ||
| 250 | + // 如果是文件夹,只创建文件夹,直接返回,无需读写文件 | ||
| 251 | + if (index == zipEntryName.length() - 1 || index == -1) { | ||
| 252 | + getDirectoryFile(parentFile, zipEntryName); | ||
| 253 | + continue; | ||
| 254 | + } else { | ||
| 255 | + // 获取文件的名称 | ||
| 256 | + String substring = zipEntryName.substring(0, index); | ||
| 257 | + // 创建父文件目录 | ||
| 258 | + file = getDirectoryFile(parentFile, substring); | ||
| 259 | + // 创建文件 | ||
| 260 | + file = getFile(file, zipEntryName.substring(index + 1)); | ||
| 261 | + } | ||
| 262 | + out = new FileOutputStream(file); | ||
| 263 | + byte[] buf1 = new byte[1024]; | ||
| 264 | + int len; | ||
| 265 | + while ((len = in.read(buf1)) > 0) { | ||
| 266 | + out.write(buf1, 0, len); | ||
| 267 | + } | ||
| 268 | + } finally { | ||
| 269 | + if (out != null) { | ||
| 270 | + out.flush(); | ||
| 271 | + out.close(); | ||
| 272 | + } | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | + } catch (IOException e) { | ||
| 276 | + throw new ContextRuntimeException("File = " + unZipFile.getName() + " unzip failed."); | ||
| 277 | + } | ||
| 278 | + if (Optional.ofNullable(isDeleteZipFile).orElse(Boolean.FALSE)) { | ||
| 279 | + FileUtils.deleteQuietly(unZipFile); | ||
| 280 | + } | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + /** | ||
| 284 | + * 压缩文件 | ||
| 285 | + * | ||
| 286 | + * @param zipFiles 待压缩的文件 | ||
| 287 | + * @param parentFile 压缩完成的文件所在目录 | ||
| 288 | + * @param isDeleteSourcesFile 是否需要删除压缩前的源文件 | ||
| 289 | + * @param zipFileName 压缩完成后的文件名称 | ||
| 290 | + * @return java.io.File 压缩完成的文件 | ||
| 291 | + * @Author yangLang | ||
| 292 | + * @Date 17:10 2020/9/2 | ||
| 293 | + */ | ||
| 294 | + public static File zipFile(List<File> zipFiles, File parentFile, String zipFileName, Boolean isDeleteSourcesFile) { | ||
| 295 | + Assert.isTrue(ObjectUtils.nonEmpty(zipFiles), "Depending compress file is null"); | ||
| 296 | + Assert.notNull(zipFileName, "Compress file name is null"); | ||
| 297 | + Assert.notNull(parentFile, "Parent file of unzip file is null"); | ||
| 298 | + File newFile = getFile(parentFile, zipFileName); | ||
| 299 | + Assert.notNull(newFile, "Zip file create failed"); | ||
| 300 | + try (FileOutputStream fos = new FileOutputStream(newFile); | ||
| 301 | + ZipOutputStream zos = new ZipOutputStream(fos)) { | ||
| 302 | + zipFiles.stream().forEach(item -> writeZip(item, "", zos)); | ||
| 303 | + } catch (IOException e) { | ||
| 304 | + log.error("Failed to create compressed file:{}", e.getMessage()); | ||
| 305 | + } | ||
| 306 | + if (Optional.ofNullable(isDeleteSourcesFile).orElse(Boolean.FALSE)) { | ||
| 307 | + zipFiles.stream().forEach(item -> { | ||
| 308 | + try { | ||
| 309 | + FileUtils.deleteDirectory(item); | ||
| 310 | + } catch (IOException e) { | ||
| 311 | + log.error("File = {} delete failed", item.getAbsolutePath()); | ||
| 312 | + } | ||
| 313 | + }); | ||
| 314 | + } | ||
| 315 | + return newFile; | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + /** | ||
| 319 | + * 写压缩文件 | ||
| 320 | + * | ||
| 321 | + * @param file 待压缩的文件夹 | ||
| 322 | + * @param parentPath 父文件路径 | ||
| 323 | + * @param zos 压缩流 | ||
| 324 | + * @return void | ||
| 325 | + * @Author yangLang | ||
| 326 | + * @Date 16:21 2020/8/6 | ||
| 327 | + */ | ||
| 328 | + private static void writeZip(File file, String parentPath, ZipOutputStream zos) { | ||
| 329 | + if (!file.exists()) { | ||
| 330 | + log.error("File = {} does not exist", file.getAbsolutePath()); | ||
| 331 | + return; | ||
| 332 | + } | ||
| 333 | + if (!file.isDirectory()) { | ||
| 334 | + zipWrite2File(file, parentPath, zos); | ||
| 335 | + return; | ||
| 336 | + } | ||
| 337 | + File[] subFiles = file.listFiles(); | ||
| 338 | + String subParentPath = parentPath + file.getName() + File.separator; | ||
| 339 | + // 空目录则创建当前目录 | ||
| 340 | + if (subFiles.length == 0) { | ||
| 341 | + try { | ||
| 342 | + zos.putNextEntry(new ZipEntry(subParentPath)); | ||
| 343 | + } catch (IOException e) { | ||
| 344 | + log.warn("{} Folder is empty", subParentPath); | ||
| 345 | + } | ||
| 346 | + return; | ||
| 347 | + } | ||
| 348 | + // 如果目录下包含文件,则递归压缩子文件 | ||
| 349 | + Arrays.stream(subFiles).forEach(item -> writeZip(item, subParentPath, zos)); | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + /** | ||
| 353 | + * 压缩文件的时候写文件 | ||
| 354 | + * | ||
| 355 | + * @param file 文件 | ||
| 356 | + * @param parentPath 父目录 | ||
| 357 | + * @param zos 压缩流 | ||
| 358 | + * @return void | ||
| 359 | + * @Author yangLang | ||
| 360 | + * @Date 16:29 2020/8/6 | ||
| 361 | + */ | ||
| 362 | + private static void zipWrite2File(File file, String parentPath, ZipOutputStream zos) { | ||
| 363 | + ZipEntry ze = new ZipEntry(parentPath + file.getName()); | ||
| 364 | + try (FileInputStream fis = new FileInputStream(file)) { | ||
| 365 | + zos.putNextEntry(ze); | ||
| 366 | + byte[] content = new byte[1024]; | ||
| 367 | + int len; | ||
| 368 | + while ((len = fis.read(content)) != -1) { | ||
| 369 | + zos.write(content, 0, len); | ||
| 370 | + zos.flush(); | ||
| 371 | + } | ||
| 372 | + } catch (Exception e) { | ||
| 373 | + log.error("Failed to compress file = {}:{}", file.getName(), e.getMessage()); | ||
| 374 | + } | ||
| 375 | + } | ||
| 376 | +} |