123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- package com.ruoyi.common.utils.file;
- import com.ruoyi.common.config.RuoYiConfig;
- import com.ruoyi.common.utils.DateUtils;
- import com.ruoyi.common.utils.StringUtils;
- import com.ruoyi.common.utils.uuid.IdUtils;
- import net.coobird.thumbnailator.Thumbnails;
- import org.apache.commons.fileupload.disk.DiskFileItem;
- import org.apache.commons.io.FilenameUtils;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang3.ArrayUtils;
- import org.apache.tika.Tika;
- import org.springframework.mock.web.MockMultipartFile;
- import org.springframework.web.multipart.MultipartFile;
- import org.springframework.web.multipart.commons.CommonsMultipartFile;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.*;
- import java.net.URL;
- import java.net.URLEncoder;
- import java.nio.charset.StandardCharsets;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 文件处理工具类
- *
- * @author ruoyi
- */
- public class FileUtils {
- public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
- /**
- * 输出指定文件的byte数组
- *
- * @param filePath 文件路径
- * @param os 输出流
- * @return
- */
- public static void writeBytes(String filePath, OutputStream os) throws IOException {
- FileInputStream fis = null;
- try {
- File file = new File(filePath);
- if (!file.exists()) {
- throw new FileNotFoundException(filePath);
- }
- fis = new FileInputStream(file);
- byte[] b = new byte[1024];
- int length;
- while ((length = fis.read(b)) > 0) {
- os.write(b, 0, length);
- }
- } catch (IOException e) {
- throw e;
- } finally {
- IOUtils.close(os);
- IOUtils.close(fis);
- }
- }
- /**
- * 写数据到文件中
- *
- * @param data 数据
- * @return 目标文件
- * @throws IOException IO异常
- */
- public static String writeImportBytes(byte[] data) throws IOException {
- return writeBytes(data, RuoYiConfig.getImportPath());
- }
- /**
- * 写数据到文件中
- *
- * @param data 数据
- * @param uploadDir 目标文件
- * @return 目标文件
- * @throws IOException IO异常
- */
- public static String writeBytes(byte[] data, String uploadDir) throws IOException {
- FileOutputStream fos = null;
- String pathName = "";
- try {
- String extension = getFileExtendName(data);
- pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
- File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
- fos = new FileOutputStream(file);
- fos.write(data);
- } finally {
- IOUtils.close(fos);
- }
- return FileUploadUtils.getPathFileName(uploadDir, pathName);
- }
- /**
- * 删除文件
- *
- * @param filePath 文件
- * @return
- */
- public static boolean deleteFile(String filePath) {
- boolean flag = false;
- File file = new File(filePath);
- // 路径为文件且不为空则进行删除
- if (file.isFile() && file.exists()) {
- flag = file.delete();
- }
- return flag;
- }
- /**
- * 文件名称验证
- *
- * @param filename 文件名称
- * @return true 正常 false 非法
- */
- public static boolean isValidFilename(String filename) {
- return filename.matches(FILENAME_PATTERN);
- }
- /**
- * 检查文件是否可下载
- *
- * @param resource 需要下载的文件
- * @return true 正常 false 非法
- */
- public static boolean checkAllowDownload(String resource) {
- // 禁止目录上跳级别
- if (StringUtils.contains(resource, "..")) {
- return false;
- }
- // 检查允许下载的文件规则
- if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) {
- return true;
- }
- // 不在允许下载的文件规则
- return false;
- }
- /**
- * 下载文件名重新编码
- *
- * @param request 请求对象
- * @param fileName 文件名
- * @return 编码后的文件名
- */
- public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
- final String agent = request.getHeader("USER-AGENT");
- String filename = fileName;
- if (agent.contains("MSIE")) {
- // IE浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- filename = filename.replace("+", " ");
- } else if (agent.contains("Firefox")) {
- // 火狐浏览器
- filename = new String(fileName.getBytes(), "ISO8859-1");
- } else if (agent.contains("Chrome")) {
- // google浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- } else {
- // 其它浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- }
- return filename;
- }
- /**
- * 下载文件名重新编码
- *
- * @param response 响应对象
- * @param realFileName 真实文件名
- */
- public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
- String percentEncodedFileName = percentEncode(realFileName);
- StringBuilder contentDispositionValue = new StringBuilder();
- contentDispositionValue.append("attachment; filename=")
- .append(percentEncodedFileName)
- .append(";")
- .append("filename*=")
- .append("utf-8''")
- .append(percentEncodedFileName);
- response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
- response.setHeader("Content-disposition", contentDispositionValue.toString());
- response.setHeader("download-filename", percentEncodedFileName);
- }
- /**
- * 百分号编码工具方法
- *
- * @param s 需要百分号编码的字符串
- * @return 百分号编码后的字符串
- */
- public static String percentEncode(String s) throws UnsupportedEncodingException {
- String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
- return encode.replaceAll("\\+", "%20");
- }
- /**
- * 获取图像后缀
- *
- * @param photoByte 图像数据
- * @return 后缀名
- */
- public static String getFileExtendName(byte[] photoByte) {
- String strFileExtendName = "jpg";
- if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
- && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) {
- strFileExtendName = "gif";
- } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) {
- strFileExtendName = "jpg";
- } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
- strFileExtendName = "bmp";
- } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) {
- strFileExtendName = "png";
- }
- return strFileExtendName;
- }
- /**
- * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
- *
- * @param fileName 路径名称
- * @return 没有文件路径的名称
- */
- public static String getName(String fileName) {
- if (fileName == null) {
- return null;
- }
- int lastUnixPos = fileName.lastIndexOf('/');
- int lastWindowsPos = fileName.lastIndexOf('\\');
- int index = Math.max(lastUnixPos, lastWindowsPos);
- return fileName.substring(index + 1);
- }
- /**
- * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
- *
- * @param fileName 路径名称
- * @return 没有文件路径和后缀的名称
- */
- public static String getNameNotSuffix(String fileName) {
- if (fileName == null) {
- return null;
- }
- String baseName = FilenameUtils.getBaseName(fileName);
- return baseName;
- }
- /**
- * 区分上传的文件是什么类型
- *
- * @param file 文件流
- * @return 类型
- */
- public static String getFileType(MultipartFile file) {
- Tika tika = new Tika();
- try {
- String mimeType = tika.detect(file.getInputStream());
- if (mimeType.startsWith("image/")) {
- return "image";
- } else if (mimeType.startsWith("audio/")) {
- return "audio";
- } else if (mimeType.startsWith("video/")) {
- return "video";
- } else {
- return "other";
- }
- } catch (IOException e) {
- e.printStackTrace();
- return "other";
- }
- }
- /**
- * 获取文件类型(图片、音频、视频等)
- *
- * @param fileUrl 文件的URL
- * @return 文件类型
- */
- public static String getFileTypeFromUrl(String fileUrl) throws IOException {
- URL url = new URL(fileUrl);
-
- // 设置连接属性
- java.net.HttpURLConnection connection = null;
- try {
- // 检查是否需要设置代理
- String proxyHost = System.getProperty("http.proxyHost");
- String proxyPort = System.getProperty("http.proxyPort");
-
- if (StringUtils.isNotEmpty(proxyHost) && StringUtils.isNotEmpty(proxyPort)) {
- // 使用系统配置的代理
- java.net.Proxy proxy = new java.net.Proxy(
- java.net.Proxy.Type.HTTP,
- new java.net.InetSocketAddress(proxyHost, Integer.parseInt(proxyPort))
- );
- connection = (java.net.HttpURLConnection) url.openConnection(proxy);
- } else {
- connection = (java.net.HttpURLConnection) url.openConnection();
- }
-
- // 设置连接参数
- connection.setConnectTimeout(5000); // 5秒连接超时
- connection.setReadTimeout(5000); // 5秒读取超时
- connection.setRequestMethod("GET");
- connection.setDoInput(true);
-
- // 尝试连接
- connection.connect();
-
- try (InputStream inputStream = connection.getInputStream()) {
- Tika tika = new Tika();
- String mimeType = tika.detect(inputStream);
- if (mimeType.startsWith("image/")) {
- return "image";
- } else if (mimeType.startsWith("audio/")) {
- return "audio";
- } else if (mimeType.startsWith("video/")) {
- return "video";
- } else {
- return "other";
- }
- }
- } catch (java.net.SocketException e) {
- // 处理网络权限错误
- System.err.println("网络连接权限被拒绝: " + e.getMessage());
- // 尝试从URL路径推断文件类型
- String path = url.getPath();
- String extension = FilenameUtils.getExtension(path).toLowerCase();
-
- // 根据扩展名判断文件类型
- if (MimeTypeUtils.isImage(extension)) {
- return "image";
- } else if (MimeTypeUtils.isAudio(extension)) {
- return "audio";
- } else if (MimeTypeUtils.isVideo(extension)) {
- return "video";
- } else {
- return "other";
- }
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- }
- }
- /**
- * 截取视频的指定时间帧,生成图片文件
- *
- * @param source 源文件
- * @param file 图片文件
- * @param time 截图时间 HH:mm:ss.[SSS]
- * @throws IOException
- * @throws InterruptedException
- */
- public static boolean screenShots(String source, String file, String time) throws IOException, InterruptedException {
- List<String> commands = new ArrayList<>();
- commands.add("ffmpeg");
- commands.add("-i");
- commands.add(source);
- commands.add("-ss");
- commands.add(time);
- commands.add("-y");
- commands.add("-q:v");
- commands.add("1");
- commands.add("-frames:v");
- commands.add("1");
- commands.add("-f");
- commands.add("image2");
- commands.add(file);
- Process process = new ProcessBuilder(commands).start();
- // 读取进程标准输出
- new Thread(() -> {
- try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
- String line = null;
- while ((line = bufferedReader.readLine()) != null) {
- System.out.println(line);
- }
- } catch (IOException e) {
- }
- }).start();
- // 读取进程异常输出
- new Thread(() -> {
- try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
- String line = null;
- while ((line = bufferedReader.readLine()) != null) {
- System.out.println(line);
- }
- } catch (IOException e) {
- }
- }).start();
- if (process.waitFor() != 0) {
- return false;
- }
- OssUtils.uploadFile(file);
- return true;
- }
- /**
- * File转换MultipartFile
- *
- * @param file 文件
- * @return MultipartFile
- * @throws Exception 异常
- */
- public static MultipartFile convertFileToMultipartFile(File file) throws Exception {
- DiskFileItem fileItem = new DiskFileItem("file", "image/jpg", true, file.getName(), (int) file.length(), file.getParentFile());
- try (FileInputStream input = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()) {
- IOUtils.copy(input, os);
- }
- return new CommonsMultipartFile(fileItem);
- }
- public static MultipartFile convertToJpg(MultipartFile file) throws IOException {
- byte[] bytes = file.getBytes();
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- Thumbnails.of(new ByteArrayInputStream(bytes))
- .scale(1)
- .outputFormat("jpg")
- .toOutputStream(outputStream);
- return new MockMultipartFile(
- file.getName(),
- file.getOriginalFilename().replaceAll("\\.[^.]+$", ".jpg"),
- "image/jpeg",
- outputStream.toByteArray()
- );
- }
- /**
- * 清理临时文件
- *
- * @param fileName 文件名称
- */
- public static void cleanTempDir(String fileName) {
- String tempDirPath = System.getProperty("java.io.tmpdir");
- File tempDir = new File(tempDirPath);
- if (tempDir.exists() && tempDir.isDirectory()) {
- File[] files = tempDir.listFiles();
- if (files != null) {
- for (File file : files) {
- // 检查是否是临时文件,并尝试删除
- if (file.isFile() && file.getName().endsWith(".tmp") || file.getName().startsWith(fileName)) {
- boolean deleted = file.delete();
- if (deleted) {
- System.out.println("删除临时文件成功: " + file.getName());
- } else {
- System.out.println("删除临时文件失败: " + file.getName());
- }
- }
- }
- }
- }
- }
- }
|