FileUtils.java 10 KB

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