|
@@ -16,18 +16,10 @@ import shop.alien.util.common.VideoUtils;
|
|
|
import shop.alien.util.file.FileUtil;
|
|
import shop.alien.util.file.FileUtil;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.File;
|
|
|
-import java.io.FileOutputStream;
|
|
|
|
|
-import java.io.InputStream;
|
|
|
|
|
-import java.nio.channels.Channels;
|
|
|
|
|
-import java.nio.channels.FileChannel;
|
|
|
|
|
-import java.nio.channels.ReadableByteChannel;
|
|
|
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Files;
|
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Path;
|
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.Paths;
|
|
|
-import java.nio.file.StandardOpenOption;
|
|
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
-import java.util.concurrent.*;
|
|
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 二期-文件上传
|
|
* 二期-文件上传
|
|
@@ -126,7 +118,7 @@ public class FileUploadUtil {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 上传多个文件(性能优化版 - 并行处理 + 流式复制)
|
|
|
|
|
|
|
+ * 上传多个文件
|
|
|
*
|
|
*
|
|
|
* @param multipartRequest 多文件
|
|
* @param multipartRequest 多文件
|
|
|
* @return List<String>
|
|
* @return List<String>
|
|
@@ -135,173 +127,82 @@ public class FileUploadUtil {
|
|
|
try {
|
|
try {
|
|
|
log.info("FileUpload.uploadMoreFile multipartRequest={}", multipartRequest.getFileNames());
|
|
log.info("FileUpload.uploadMoreFile multipartRequest={}", multipartRequest.getFileNames());
|
|
|
Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
|
|
Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
|
|
|
- String uploadDir = this.uploadDir.replace("file:///", "").replace("\\", "/");
|
|
|
|
|
-
|
|
|
|
|
- // 如果只有一个文件,直接处理(避免线程池开销)
|
|
|
|
|
- if (fileNameSet.size() == 1) {
|
|
|
|
|
- return uploadMoreFileSequential(multipartRequest, fileNameSet, uploadDir);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 多个文件使用并行处理
|
|
|
|
|
- List<CompletableFuture<List<String>>> futures = new ArrayList<>();
|
|
|
|
|
- ExecutorService executor = createUploadExecutor();
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- for (String s : fileNameSet) {
|
|
|
|
|
- MultipartFile multipartFile = multipartRequest.getFileMap().get(s);
|
|
|
|
|
- CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
|
|
|
|
|
- return processSingleFile(multipartFile, uploadDir);
|
|
|
|
|
- }, executor);
|
|
|
|
|
- futures.add(future);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 等待所有任务完成并合并结果
|
|
|
|
|
- List<String> filePathList = new ArrayList<>();
|
|
|
|
|
- for (CompletableFuture<List<String>> future : futures) {
|
|
|
|
|
- try {
|
|
|
|
|
- filePathList.addAll(future.get());
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("处理文件失败", e);
|
|
|
|
|
- throw new RuntimeException("文件处理失败: " + e.getMessage(), e);
|
|
|
|
|
|
|
+ List<String> filePathList = new ArrayList<>();
|
|
|
|
|
+ for (String s : fileNameSet) {
|
|
|
|
|
+ MultipartFile multipartFile = multipartRequest.getFileMap().get(s);
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile fileName={}", multipartFile.getOriginalFilename());
|
|
|
|
|
+ String uploadDir = this.uploadDir.replace("file:///", "").replace("\\", "/");
|
|
|
|
|
+ String prefix;
|
|
|
|
|
+ Map<String, String> fileNameAndType = FileUtil.getFileNameAndType(multipartFile);
|
|
|
|
|
+ //区分文件类型
|
|
|
|
|
+ if (imageFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/image";
|
|
|
|
|
+ prefix = "image/";
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到图片文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String imageFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + imageFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
+ ;
|
|
|
|
|
+ } else if (videoFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/video/";
|
|
|
|
|
+ prefix = "video/";
|
|
|
|
|
+ //上传视频文件
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到视频文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String videoFileName = fileNameAndType.get("name").replaceAll(",", "") + RandomCreateUtil.getRandomNum(6);
|
|
|
|
|
+ String cacheVideoPath = copyFile(uploadDir, multipartFile);
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + videoFileName + "." + fileNameAndType.get("type")));
|
|
|
|
|
+ //缓存视频截图使用
|
|
|
|
|
+ File videoFile = new File(cacheVideoPath);
|
|
|
|
|
+ //获取视频某帧截图
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 视频文件复制完毕, 获取第一秒图片 {}", videoFile.getName());
|
|
|
|
|
+ String videoPath = videoUtils.getImg(uploadDir + videoFile.getName());
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 视频文件复制完毕, 图片位置 {}", videoPath);
|
|
|
|
|
+ if (!videoPath.isEmpty()) {
|
|
|
|
|
+ File videoImgFile = new File(videoPath);
|
|
|
|
|
+ Map<String, String> videoImg = FileUtil.getFileNameAndType(videoImgFile);
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(videoImgFile, prefix + videoFileName + "." + videoImg.get("type")));
|
|
|
|
|
+ videoImgFile.delete();
|
|
|
|
|
+ videoFile.delete();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new RuntimeException("视频截图失败");
|
|
|
}
|
|
}
|
|
|
|
|
+ } else if (voiceFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/voice";
|
|
|
|
|
+ prefix = "voice/";
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到语音文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String voiceFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + voiceFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
+ } else if (privacyFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/privacy/";
|
|
|
|
|
+ prefix = "privacy/";
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到隐私文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String privacyFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + privacyFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
+ } else if (pdfFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/pdf";
|
|
|
|
|
+ prefix = "pdf/";
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到PDF文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String pdfFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + pdfFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
+ } else if (ohterFileType.contains(fileNameAndType.get("type").toLowerCase())) {
|
|
|
|
|
+ uploadDir += "/other/";
|
|
|
|
|
+ prefix = "other/";
|
|
|
|
|
+ log.info("FileUpload.uploadMoreFile 获取到其他文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
+ // 去除文件名中的逗号,避免URL拼接时被错误分割
|
|
|
|
|
+ String otherFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
+ filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + otherFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return filePathList;
|
|
|
|
|
- } finally {
|
|
|
|
|
- executor.shutdown();
|
|
|
|
|
}
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("FileUpload.uploadMoreFile ERROR Msg={}", e.getMessage(), e);
|
|
|
|
|
- throw new RuntimeException(e);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 顺序处理(单个文件时使用,避免线程池开销)
|
|
|
|
|
- */
|
|
|
|
|
- private List<String> uploadMoreFileSequential(MultipartRequest multipartRequest, Set<String> fileNameSet, String uploadDir) {
|
|
|
|
|
- List<String> filePathList = new ArrayList<>();
|
|
|
|
|
- for (String s : fileNameSet) {
|
|
|
|
|
- MultipartFile multipartFile = multipartRequest.getFileMap().get(s);
|
|
|
|
|
- filePathList.addAll(processSingleFile(multipartFile, uploadDir));
|
|
|
|
|
- }
|
|
|
|
|
- return filePathList;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 处理单个文件
|
|
|
|
|
- */
|
|
|
|
|
- private List<String> processSingleFile(MultipartFile multipartFile, String baseUploadDir) {
|
|
|
|
|
- List<String> filePathList = new ArrayList<>();
|
|
|
|
|
- try {
|
|
|
|
|
- log.info("FileUpload.processSingleFile fileName={}", multipartFile.getOriginalFilename());
|
|
|
|
|
- String uploadDir = baseUploadDir;
|
|
|
|
|
- String prefix;
|
|
|
|
|
- Map<String, String> fileNameAndType = FileUtil.getFileNameAndType(multipartFile);
|
|
|
|
|
- String fileType = fileNameAndType.get("type").toLowerCase();
|
|
|
|
|
-
|
|
|
|
|
- //区分文件类型
|
|
|
|
|
- if (imageFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/image";
|
|
|
|
|
- prefix = "image/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到图片文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String imageFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + imageFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
-
|
|
|
|
|
- } else if (videoFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/video/";
|
|
|
|
|
- prefix = "video/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到视频文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String videoFileName = fileNameAndType.get("name").replaceAll(",", "") + RandomCreateUtil.getRandomNum(6);
|
|
|
|
|
-
|
|
|
|
|
- // 优化:并行执行视频上传和文件复制(这两个操作互不依赖,可以并行)
|
|
|
|
|
- CompletableFuture<String> uploadFuture = CompletableFuture.supplyAsync(() -> {
|
|
|
|
|
- return aliOSSUtil.uploadFile(multipartFile, prefix + videoFileName + "." + fileNameAndType.get("type"));
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // 复制文件用于截图(使用优化的流式复制)
|
|
|
|
|
- String cacheVideoPath = copyFileOptimized(uploadDir, multipartFile);
|
|
|
|
|
- File videoFile = new File(cacheVideoPath);
|
|
|
|
|
-
|
|
|
|
|
- // 等待上传完成(如果复制已完成,这里不会阻塞太久)
|
|
|
|
|
- String videoUrl = uploadFuture.get();
|
|
|
|
|
- filePathList.add(videoUrl);
|
|
|
|
|
-
|
|
|
|
|
- // 获取视频截图
|
|
|
|
|
- log.info("FileUpload.processSingleFile 视频文件复制完毕, 获取第一秒图片 {}", videoFile.getName());
|
|
|
|
|
- String videoPath = videoUtils.getImg(uploadDir + videoFile.getName());
|
|
|
|
|
- log.info("FileUpload.processSingleFile 视频文件复制完毕, 图片位置 {}", videoPath);
|
|
|
|
|
-
|
|
|
|
|
- if (!videoPath.isEmpty()) {
|
|
|
|
|
- File videoImgFile = new File(videoPath);
|
|
|
|
|
- Map<String, String> videoImg = FileUtil.getFileNameAndType(videoImgFile);
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(videoImgFile, prefix + videoFileName + "." + videoImg.get("type")));
|
|
|
|
|
- videoImgFile.delete();
|
|
|
|
|
- videoFile.delete();
|
|
|
|
|
- } else {
|
|
|
|
|
- throw new RuntimeException("视频截图失败");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } else if (voiceFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/voice";
|
|
|
|
|
- prefix = "voice/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到语音文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String voiceFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + voiceFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
-
|
|
|
|
|
- } else if (privacyFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/privacy/";
|
|
|
|
|
- prefix = "privacy/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到隐私文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String privacyFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + privacyFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
-
|
|
|
|
|
- } else if (pdfFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/pdf";
|
|
|
|
|
- prefix = "pdf/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到PDF文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String pdfFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + pdfFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
-
|
|
|
|
|
- } else if (ohterFileType.contains(fileType)) {
|
|
|
|
|
- uploadDir += "/other/";
|
|
|
|
|
- prefix = "other/";
|
|
|
|
|
- log.info("FileUpload.processSingleFile 获取到其他文件准备上传 {} {}", prefix, multipartFile.getOriginalFilename());
|
|
|
|
|
- String otherFileName = fileNameAndType.get("name").replaceAll(",", "");
|
|
|
|
|
- filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + otherFileName + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return filePathList;
|
|
return filePathList;
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log.error("FileUpload.processSingleFile ERROR fileName={}, Msg={}", multipartFile.getOriginalFilename(), e.getMessage(), e);
|
|
|
|
|
- throw new RuntimeException("处理文件失败: " + multipartFile.getOriginalFilename(), e);
|
|
|
|
|
|
|
+ log.error("FileUpload.uploadMoreFile ERROR Msg={}", e.getMessage());
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 创建上传任务线程池
|
|
|
|
|
- */
|
|
|
|
|
- private ExecutorService createUploadExecutor() {
|
|
|
|
|
- int corePoolSize = Math.min(Runtime.getRuntime().availableProcessors() * 2, 8);
|
|
|
|
|
- int maxPoolSize = Math.min(Runtime.getRuntime().availableProcessors() * 4, 16);
|
|
|
|
|
- return new ThreadPoolExecutor(
|
|
|
|
|
- corePoolSize,
|
|
|
|
|
- maxPoolSize,
|
|
|
|
|
- 60L,
|
|
|
|
|
- TimeUnit.SECONDS,
|
|
|
|
|
- new LinkedBlockingQueue<>(100),
|
|
|
|
|
- new ThreadFactory() {
|
|
|
|
|
- private int count = 0;
|
|
|
|
|
- @Override
|
|
|
|
|
- public Thread newThread(Runnable r) {
|
|
|
|
|
- Thread t = new Thread(r);
|
|
|
|
|
- t.setName("file-upload-" + count++);
|
|
|
|
|
- return t;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- new ThreadPoolExecutor.CallerRunsPolicy()
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 上传图片
|
|
* 上传图片
|
|
@@ -349,92 +250,30 @@ public class FileUploadUtil {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 复制文件, 返回url链接(优化版 - 使用流式复制,避免一次性读取大文件)
|
|
|
|
|
|
|
+ * 复制文件, 返回url链接
|
|
|
*
|
|
*
|
|
|
* @param localFilePath 本地路径
|
|
* @param localFilePath 本地路径
|
|
|
* @param file 文件
|
|
* @param file 文件
|
|
|
* @return 访问url路径
|
|
* @return 访问url路径
|
|
|
*/
|
|
*/
|
|
|
private String copyFile(String localFilePath, MultipartFile file) {
|
|
private String copyFile(String localFilePath, MultipartFile file) {
|
|
|
- return copyFileOptimized(localFilePath, file);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 优化的文件复制方法 - 使用流式复制,避免一次性读取全部字节
|
|
|
|
|
- * 对于大文件(如视频),性能提升显著
|
|
|
|
|
- *
|
|
|
|
|
- * @param localFilePath 本地路径
|
|
|
|
|
- * @param file 文件
|
|
|
|
|
- * @return 访问url路径
|
|
|
|
|
- */
|
|
|
|
|
- private String copyFileOptimized(String localFilePath, MultipartFile file) {
|
|
|
|
|
- InputStream inputStream = null;
|
|
|
|
|
- FileOutputStream outputStream = null;
|
|
|
|
|
- ReadableByteChannel inputChannel = null;
|
|
|
|
|
- FileChannel outputChannel = null;
|
|
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
File cacheFilePath = new File(localFilePath);
|
|
File cacheFilePath = new File(localFilePath);
|
|
|
if (!cacheFilePath.exists()) {
|
|
if (!cacheFilePath.exists()) {
|
|
|
cacheFilePath.mkdirs();
|
|
cacheFilePath.mkdirs();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- String fileName = file.getOriginalFilename();
|
|
|
|
|
- Path path = Paths.get(localFilePath, fileName);
|
|
|
|
|
|
|
+ String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.'));
|
|
|
|
|
+ log.info("FileUpload.copyFile fileName={}", fileName);
|
|
|
|
|
+ String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
|
|
|
|
|
+ log.info("FileUpload.copyFile fileType={}", fileType);
|
|
|
|
|
+ System.out.println(file.getOriginalFilename());
|
|
|
|
|
+ Path path = Paths.get(localFilePath, file.getOriginalFilename());
|
|
|
Files.createDirectories(path.getParent());
|
|
Files.createDirectories(path.getParent());
|
|
|
-
|
|
|
|
|
- // 使用NIO的Channel进行高效复制(零拷贝技术)
|
|
|
|
|
- File targetFile = path.toFile();
|
|
|
|
|
- inputStream = file.getInputStream();
|
|
|
|
|
- outputStream = new FileOutputStream(targetFile);
|
|
|
|
|
-
|
|
|
|
|
- // 将InputStream转换为ReadableByteChannel
|
|
|
|
|
- inputChannel = Channels.newChannel(inputStream);
|
|
|
|
|
- outputChannel = outputStream.getChannel();
|
|
|
|
|
-
|
|
|
|
|
- // 使用transferFrom进行高效复制,对于大文件性能更好
|
|
|
|
|
- // 对于大文件,分块传输以避免内存问题
|
|
|
|
|
- long transferred = 0;
|
|
|
|
|
- long fileSize = file.getSize();
|
|
|
|
|
- long chunkSize = 8 * 1024 * 1024; // 8MB chunks
|
|
|
|
|
-
|
|
|
|
|
- while (transferred < fileSize) {
|
|
|
|
|
- long remaining = fileSize - transferred;
|
|
|
|
|
- long toTransfer = Math.min(chunkSize, remaining);
|
|
|
|
|
- transferred += outputChannel.transferFrom(inputChannel, transferred, toTransfer);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return localFilePath + fileName;
|
|
|
|
|
|
|
+ Files.write(path, file.getBytes());
|
|
|
|
|
+ return localFilePath + file.getOriginalFilename();
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log.error("FileUpload.copyFileOptimized ERROR Msg={}", e.getMessage(), e);
|
|
|
|
|
- // 降级到传统方式
|
|
|
|
|
- try {
|
|
|
|
|
- Path path = Paths.get(localFilePath, file.getOriginalFilename());
|
|
|
|
|
- Files.createDirectories(path.getParent());
|
|
|
|
|
- // 使用缓冲流进行复制
|
|
|
|
|
- try (InputStream is = file.getInputStream();
|
|
|
|
|
- FileOutputStream fos = new FileOutputStream(path.toFile())) {
|
|
|
|
|
- byte[] buffer = new byte[8192];
|
|
|
|
|
- int bytesRead;
|
|
|
|
|
- while ((bytesRead = is.read(buffer)) != -1) {
|
|
|
|
|
- fos.write(buffer, 0, bytesRead);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return localFilePath + file.getOriginalFilename();
|
|
|
|
|
- } catch (Exception ex) {
|
|
|
|
|
- log.error("FileUpload.copyFileOptimized 降级方案也失败 Msg={}", ex.getMessage(), ex);
|
|
|
|
|
- throw new RuntimeException("文件复制失败: " + ex.getMessage(), ex);
|
|
|
|
|
- }
|
|
|
|
|
- } finally {
|
|
|
|
|
- // 关闭资源
|
|
|
|
|
- try {
|
|
|
|
|
- if (inputChannel != null) inputChannel.close();
|
|
|
|
|
- if (outputChannel != null) outputChannel.close();
|
|
|
|
|
- if (inputStream != null) inputStream.close();
|
|
|
|
|
- if (outputStream != null) outputStream.close();
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.warn("关闭文件流失败", e);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ log.error("FileUpload.copyFile ERROR Msg={}", e.getMessage());
|
|
|
|
|
+ return e.getMessage();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|