FileUtils.java 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package com.ruoyi.common.utils.file;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.io.UnsupportedEncodingException;
  9. import java.net.URLEncoder;
  10. import java.nio.charset.StandardCharsets;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import org.apache.commons.io.FilenameUtils;
  14. import org.apache.commons.io.IOUtils;
  15. import org.apache.commons.lang3.ArrayUtils;
  16. import com.ruoyi.common.config.RuoYiConfig;
  17. import com.ruoyi.common.constant.Constants;
  18. import com.ruoyi.common.utils.DateUtils;
  19. import com.ruoyi.common.utils.StringUtils;
  20. import com.ruoyi.common.utils.uuid.IdUtils;
  21. import org.springframework.web.multipart.MultipartFile;
  22. /**
  23. * 文件处理工具类
  24. *
  25. * @author ruoyi
  26. */
  27. public class FileUtils
  28. {
  29. public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
  30. /**
  31. * 输出指定文件的byte数组
  32. *
  33. * @param filePath 文件路径
  34. * @param os 输出流
  35. * @return
  36. */
  37. public static void writeBytes(String filePath, OutputStream os) throws IOException
  38. {
  39. FileInputStream fis = null;
  40. try
  41. {
  42. File file = new File(filePath);
  43. if (!file.exists())
  44. {
  45. throw new FileNotFoundException(filePath);
  46. }
  47. fis = new FileInputStream(file);
  48. byte[] b = new byte[1024];
  49. int length;
  50. while ((length = fis.read(b)) > 0)
  51. {
  52. os.write(b, 0, length);
  53. }
  54. }
  55. catch (IOException e)
  56. {
  57. throw e;
  58. }
  59. finally
  60. {
  61. IOUtils.close(os);
  62. IOUtils.close(fis);
  63. }
  64. }
  65. /**
  66. * 写数据到文件中
  67. *
  68. * @param data 数据
  69. * @return 目标文件
  70. * @throws IOException IO异常
  71. */
  72. public static String writeImportBytes(byte[] data) throws IOException
  73. {
  74. return writeBytes(data, RuoYiConfig.getImportPath());
  75. }
  76. /**
  77. * 写数据到文件中
  78. *
  79. * @param data 数据
  80. * @param uploadDir 目标文件
  81. * @return 目标文件
  82. * @throws IOException IO异常
  83. */
  84. public static String writeBytes(byte[] data, String uploadDir) throws IOException
  85. {
  86. FileOutputStream fos = null;
  87. String pathName = "";
  88. try
  89. {
  90. String extension = getFileExtendName(data);
  91. pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
  92. File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
  93. fos = new FileOutputStream(file);
  94. fos.write(data);
  95. }
  96. finally
  97. {
  98. IOUtils.close(fos);
  99. }
  100. return FileUploadUtils.getPathFileName(uploadDir, pathName);
  101. }
  102. /**
  103. * 移除路径中的请求前缀片段
  104. *
  105. * @param filePath 文件路径
  106. * @return 移除后的文件路径
  107. */
  108. public static String stripPrefix(String filePath)
  109. {
  110. return StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX);
  111. }
  112. /**
  113. * 删除文件
  114. *
  115. * @param filePath 文件
  116. * @return
  117. */
  118. public static boolean deleteFile(String filePath)
  119. {
  120. boolean flag = false;
  121. File file = new File(filePath);
  122. // 路径为文件且不为空则进行删除
  123. if (file.isFile() && file.exists())
  124. {
  125. flag = file.delete();
  126. }
  127. return flag;
  128. }
  129. /**
  130. * 文件名称验证
  131. *
  132. * @param filename 文件名称
  133. * @return true 正常 false 非法
  134. */
  135. public static boolean isValidFilename(String filename)
  136. {
  137. return filename.matches(FILENAME_PATTERN);
  138. }
  139. /**
  140. * 检查文件是否可下载
  141. *
  142. * @param resource 需要下载的文件
  143. * @return true 正常 false 非法
  144. */
  145. public static boolean checkAllowDownload(String resource)
  146. {
  147. // 禁止目录上跳级别
  148. if (StringUtils.contains(resource, ".."))
  149. {
  150. return false;
  151. }
  152. // 检查允许下载的文件规则
  153. if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
  154. {
  155. return true;
  156. }
  157. // 不在允许下载的文件规则
  158. return false;
  159. }
  160. /**
  161. * 下载文件名重新编码
  162. *
  163. * @param request 请求对象
  164. * @param fileName 文件名
  165. * @return 编码后的文件名
  166. */
  167. public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
  168. {
  169. final String agent = request.getHeader("USER-AGENT");
  170. String filename = fileName;
  171. if (agent.contains("MSIE"))
  172. {
  173. // IE浏览器
  174. filename = URLEncoder.encode(filename, "utf-8");
  175. filename = filename.replace("+", " ");
  176. }
  177. else if (agent.contains("Firefox"))
  178. {
  179. // 火狐浏览器
  180. filename = new String(fileName.getBytes(), "ISO8859-1");
  181. }
  182. else if (agent.contains("Chrome"))
  183. {
  184. // google浏览器
  185. filename = URLEncoder.encode(filename, "utf-8");
  186. }
  187. else
  188. {
  189. // 其它浏览器
  190. filename = URLEncoder.encode(filename, "utf-8");
  191. }
  192. return filename;
  193. }
  194. /**
  195. * 下载文件名重新编码
  196. *
  197. * @param response 响应对象
  198. * @param realFileName 真实文件名
  199. */
  200. public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
  201. {
  202. String percentEncodedFileName = percentEncode(realFileName);
  203. StringBuilder contentDispositionValue = new StringBuilder();
  204. contentDispositionValue.append("attachment; filename=")
  205. .append(percentEncodedFileName)
  206. .append(";")
  207. .append("filename*=")
  208. .append("utf-8''")
  209. .append(percentEncodedFileName);
  210. response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
  211. response.setHeader("Content-disposition", contentDispositionValue.toString());
  212. response.setHeader("download-filename", percentEncodedFileName);
  213. }
  214. /**
  215. * 百分号编码工具方法
  216. *
  217. * @param s 需要百分号编码的字符串
  218. * @return 百分号编码后的字符串
  219. */
  220. public static String percentEncode(String s) throws UnsupportedEncodingException
  221. {
  222. String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
  223. return encode.replaceAll("\\+", "%20");
  224. }
  225. /**
  226. * 获取图像后缀
  227. *
  228. * @param photoByte 图像数据
  229. * @return 后缀名
  230. */
  231. public static String getFileExtendName(byte[] photoByte)
  232. {
  233. String strFileExtendName = "jpg";
  234. if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
  235. && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
  236. {
  237. strFileExtendName = "gif";
  238. }
  239. else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
  240. {
  241. strFileExtendName = "jpg";
  242. }
  243. else if ((photoByte[0] == 66) && (photoByte[1] == 77))
  244. {
  245. strFileExtendName = "bmp";
  246. }
  247. else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
  248. {
  249. strFileExtendName = "png";
  250. }
  251. return strFileExtendName;
  252. }
  253. /**
  254. * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
  255. *
  256. * @param fileName 路径名称
  257. * @return 没有文件路径的名称
  258. */
  259. public static String getName(String fileName)
  260. {
  261. if (fileName == null)
  262. {
  263. return null;
  264. }
  265. int lastUnixPos = fileName.lastIndexOf('/');
  266. int lastWindowsPos = fileName.lastIndexOf('\\');
  267. int index = Math.max(lastUnixPos, lastWindowsPos);
  268. return fileName.substring(index + 1);
  269. }
  270. /**
  271. * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
  272. *
  273. * @param fileName 路径名称
  274. * @return 没有文件路径和后缀的名称
  275. */
  276. public static String getNameNotSuffix(String fileName)
  277. {
  278. if (fileName == null)
  279. {
  280. return null;
  281. }
  282. String baseName = FilenameUtils.getBaseName(fileName);
  283. return baseName;
  284. }
  285. /**
  286. * 获取文件扩展名
  287. *
  288. * @param file 表单文件
  289. * @return 扩展名
  290. */
  291. public static String getExtension(MultipartFile file)
  292. {
  293. String extension = FilenameUtils.getExtension(file.getOriginalFilename());
  294. if (StringUtils.isEmpty(extension))
  295. {
  296. extension = MimeTypeUtils.getExtension(file.getContentType());
  297. }
  298. return extension;
  299. }
  300. }