001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.utils; 017 018import com.jfinal.core.JFinal; 019import com.jfinal.kit.Base64Kit; 020import com.jfinal.kit.HashKit; 021import com.jfinal.kit.LogKit; 022import com.jfinal.kit.PathKit; 023import com.jfinal.upload.UploadFile; 024 025import java.io.*; 026import java.nio.charset.Charset; 027import java.nio.charset.StandardCharsets; 028import java.security.MessageDigest; 029import java.util.Enumeration; 030import java.util.List; 031import java.util.zip.ZipEntry; 032import java.util.zip.ZipFile; 033 034 035public class FileUtil { 036 037 /** 038 * 获取文件后缀 039 * 040 * @param fileName eg: jboot.jpg 041 * @return suffix eg: .jpg 042 */ 043 public static String getSuffix(String fileName) { 044 if (fileName != null && fileName.contains(".")) { 045 return fileName.substring(fileName.lastIndexOf(".")); 046 } 047 return null; 048 } 049 050 051 public static String removePrefix(String src, String... prefixes) { 052 if (src != null) { 053 for (String prefix : prefixes) { 054 if (src.startsWith(prefix)) { 055 return src.substring(prefix.length()); 056 } 057 } 058 } 059 060 return src; 061 } 062 063 064 public static String removeSuffix(String src, String... suffixes) { 065 if (src != null) { 066 for (String suffix : suffixes) { 067 if (src.endsWith(suffix)) { 068 return src.substring(0, suffix.length()); 069 } 070 } 071 } 072 return src; 073 } 074 075 076 public static String removeRootPath(String src) { 077 return removePrefix(src, PathKit.getWebRootPath()); 078 } 079 080 081 public static String readString(File file) { 082 return readString(file, JFinal.me().getConstants().getEncoding()); 083 } 084 085 086 public static String readString(File file, String charsetName) { 087 ByteArrayOutputStream baos = null; 088 FileInputStream fis = null; 089 try { 090 fis = new FileInputStream(file); 091 baos = new ByteArrayOutputStream(); 092 byte[] buffer = new byte[1024]; 093 for (int len = 0; (len = fis.read(buffer)) > 0; ) { 094 baos.write(buffer, 0, len); 095 } 096 return baos.toString(charsetName); 097 } catch (Exception e) { 098 LogKit.error(e.toString(), e); 099 } finally { 100 close(fis, baos); 101 } 102 return null; 103 } 104 105 106 public static void writeString(File file, String content) { 107 writeString(file, content, JFinal.me().getConstants().getEncoding()); 108 } 109 110 111 public static void writeString(File file, String content, String charsetName) { 112 writeString(file, content, charsetName, false); 113 } 114 115 public static void writeString(File file, String content, String charsetName, boolean append) { 116 FileOutputStream fos = null; 117 try { 118 ensuresParentExists(file); 119 fos = new FileOutputStream(file, append); 120 fos.write(content.getBytes(charsetName)); 121 } catch (Exception e) { 122 LogKit.error(e.toString(), e); 123 } finally { 124 close(fos); 125 } 126 } 127 128 public static void ensuresParentExists(File currentFile) throws IOException { 129 if (!currentFile.getParentFile().exists() 130 && !currentFile.getParentFile().mkdirs()) { 131 throw new IOException("Can not mkdirs for file: " + currentFile.getParentFile()); 132 } 133 } 134 135 136 /** 137 * 获取文件的 md5 138 * 139 * @param file 140 * @return 141 */ 142 public static String getFileMD5(File file) { 143 return getFileMD5(file, false); 144 } 145 146 147 /** 148 * 获取文件 md5 的 base64 编码 149 * 150 * @param file 151 * @return 152 */ 153 public static String getFileMd5Base64(File file) { 154 return getFileMD5(file, true); 155 } 156 157 158 private static String getFileMD5(File file, boolean withBase64) { 159 try (FileInputStream fiStream = new FileInputStream(file)) { 160 MessageDigest digest = MessageDigest.getInstance("MD5"); 161 byte[] buffer = new byte[8192]; 162 int length; 163 while ((length = fiStream.read(buffer)) != -1) { 164 digest.update(buffer, 0, length); 165 } 166 return withBase64 ? Base64Kit.encode(digest.digest()) : HashKit.toHex(digest.digest()); 167 } catch (Exception e) { 168 LogKit.error(e.toString(), e); 169 } 170 return null; 171 } 172 173 174 public static void close(Closeable... closeable) { 175 QuietlyUtil.closeQuietly(closeable); 176 } 177 178 179 public static void unzip(String zipFilePath) throws IOException { 180 String targetPath = zipFilePath.substring(0, zipFilePath.lastIndexOf(".")); 181 unzip(zipFilePath, targetPath, true, StandardCharsets.UTF_8); 182 } 183 184 185 public static void unzip(String zipFilePath, String targetPath) throws IOException { 186 unzip(zipFilePath, targetPath, true, StandardCharsets.UTF_8); 187 } 188 189 190 public static void unzip(String zipFilePath, String targetPath, boolean safeUnzip, Charset charset) throws IOException { 191 targetPath = getCanonicalPath(new File(targetPath)); 192 ZipFile zipFile = new ZipFile(zipFilePath, charset); 193 try { 194 Enumeration<?> entryEnum = zipFile.entries(); 195 while (entryEnum.hasMoreElements()) { 196 OutputStream os = null; 197 InputStream is = null; 198 try { 199 ZipEntry zipEntry = (ZipEntry) entryEnum.nextElement(); 200 if (!zipEntry.isDirectory()) { 201 if (safeUnzip && isNotSafeFile(zipEntry.getName())) { 202 //Unsafe 203 continue; 204 } 205 206 File targetFile = new File(targetPath, zipEntry.getName()); 207 208 ensuresParentExists(targetFile); 209 210 if (!targetFile.toPath().normalize().startsWith(targetPath)) { 211 throw new IOException("Bad zip entry"); 212 } 213 214 os = new BufferedOutputStream(new FileOutputStream(targetFile)); 215 is = zipFile.getInputStream(zipEntry); 216 byte[] buffer = new byte[4096]; 217 int readLen = 0; 218 while ((readLen = is.read(buffer, 0, 4096)) > 0) { 219 os.write(buffer, 0, readLen); 220 } 221 } 222 } finally { 223 close(is, os); 224 } 225 } 226 } finally { 227 close(zipFile); 228 } 229 } 230 231 232 private static boolean isNotSafeFile(String name) { 233 name = name.toLowerCase(); 234 return name.endsWith(".jsp") || name.endsWith(".jspx"); 235 } 236 237 238 public static boolean isAbsolutePath(String path) { 239 return StrUtil.isNotBlank(path) && (path.startsWith("/") || path.indexOf(":") > 0); 240 } 241 242 243 public static String getCanonicalPath(File file) { 244 try { 245 return file.getCanonicalPath(); 246 } catch (IOException e) { 247 throw new RuntimeException(e); 248 } 249 } 250 251 public static void delete(File file) { 252 if (file == null) { 253 return; 254 } 255 256 if (!file.delete()) { 257 LogKit.error("File {} can not deleted!", getCanonicalPath(file)); 258 } 259 } 260 261 public static void delete(UploadFile file) { 262 if (file == null) { 263 return; 264 } 265 266 delete(file.getFile()); 267 } 268 269 270 public static void delete(List<UploadFile> files) { 271 if (files == null) { 272 return; 273 } 274 275 files.forEach(FileUtil::delete); 276 } 277 278}