refactor: 重构文件管理模块
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package com.cxx.home.config;
|
||||
|
||||
import com.cxx.home.constant.FileConstant;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @Author: Cxx
|
||||
* @Date: 2024/9/22 10:57
|
||||
* @Description:
|
||||
*/
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
@Value("${file.path}")
|
||||
private String filePath;
|
||||
|
||||
@Value("${file.log-path}")
|
||||
private String logFilePath;
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/" + FileConstant.FILE_URL_PREFIX + "/**")
|
||||
.addResourceLocations("file:" + filePath);
|
||||
|
||||
registry.addResourceHandler("/" + FileConstant.FILE_LOG_PREFIX + "/**")
|
||||
.addResourceLocations("file:" + logFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.cxx.home.constant;
|
||||
|
||||
public interface FileConstant {
|
||||
String FILE_NAME_SPLIT = "_";
|
||||
String FILE_URL_PREFIX = "files";
|
||||
String FILE_LOG_PREFIX = "logs";
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.cxx.home.controller;
|
||||
|
||||
import com.cxx.home.dto.file.ChunkInfoDto;
|
||||
import com.cxx.home.dto.file.ChunkResultDto;
|
||||
import com.cxx.home.dto.file.FileInfoDto;
|
||||
import com.cxx.home.dto.file.FileRecordDto;
|
||||
import com.cxx.home.service.FileService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@Tag(name = "文件管理")
|
||||
public class FileController {
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
|
||||
@Operation(summary = "上传文件")
|
||||
@PostMapping(value = "", headers = "content-type=multipart/form-data")
|
||||
public FileRecordDto uploadFile(@RequestPart("file") MultipartFile file,
|
||||
@RequestParam("path") String path,
|
||||
@RequestParam("md5") String md5) {
|
||||
return fileService.uploadFile(file, path, md5);
|
||||
}
|
||||
|
||||
@Operation(summary = "上传文件块")
|
||||
@PostMapping("/chunk")
|
||||
public Boolean uploadChunk(ChunkInfoDto chunkInfo,
|
||||
String path) {
|
||||
return fileService.uploadChunk(chunkInfo, path);
|
||||
}
|
||||
|
||||
@Operation(summary = "验证当前文件块是否上传")
|
||||
@GetMapping("/chunk")
|
||||
public ChunkResultDto checkChunk(@RequestParam String identifier,
|
||||
@RequestParam String filename,
|
||||
@RequestParam String path) {
|
||||
return fileService.checkChunk(identifier, filename, path);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除当前已上传的文件块")
|
||||
@DeleteMapping("/chunk")
|
||||
public Boolean deleteChunk(@RequestParam String identifier,
|
||||
@RequestParam String path) {
|
||||
return fileService.deleteChunk(identifier, path);
|
||||
}
|
||||
|
||||
@Operation(summary = "合并文件")
|
||||
@PostMapping("/chunk/merge")
|
||||
public FileRecordDto mergeFile(@RequestParam String filename,
|
||||
@RequestParam String path) {
|
||||
return fileService.mergeFile(filename, path);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取文件夹目录")
|
||||
@GetMapping("/catalog")
|
||||
public List<FileInfoDto> getFolderInfo(@RequestParam String folderName) {
|
||||
return fileService.getFolderInfo(folderName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.cxx.home.dto.file;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ChunkInfoDto {
|
||||
/**
|
||||
* 当前文件块,从1开始
|
||||
*/
|
||||
private Integer chunkNumber;
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String filename;
|
||||
/**
|
||||
* 块内容
|
||||
*/
|
||||
private transient MultipartFile multipartFile;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.cxx.home.dto.file;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ChunkResultDto {
|
||||
/**
|
||||
* 是否跳过上传(已上传的可以直接跳过,达到秒传的效果)
|
||||
*/
|
||||
private boolean isSkipUpload;
|
||||
|
||||
/**
|
||||
* 已经上传的文件块编号,可以跳过,断点续传
|
||||
*/
|
||||
private List<Integer> uploadedChunkList;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.cxx.home.dto.file;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileInfoDto {
|
||||
private String name;
|
||||
private String type;
|
||||
private String size;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createDate;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.cxx.home.dto.file;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileRecordDto {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String md5;
|
||||
private String path;
|
||||
private String url;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.cxx.home.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.cxx.framework.data.AbstractEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("file_record")
|
||||
public class FileRecord extends AbstractEntity {
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
@TableField("md5")
|
||||
private String md5;
|
||||
|
||||
@TableField("path")
|
||||
private String path;
|
||||
|
||||
@TableField("url")
|
||||
private String url;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.cxx.home.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.cxx.home.entity.FileRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface FileRecordMapper extends BaseMapper<FileRecord> {
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.cxx.home.service;
|
||||
|
||||
import com.cxx.home.dto.file.ChunkInfoDto;
|
||||
import com.cxx.home.dto.file.ChunkResultDto;
|
||||
import com.cxx.home.dto.file.FileInfoDto;
|
||||
import com.cxx.home.dto.file.FileRecordDto;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FileService {
|
||||
FileRecordDto uploadFile(MultipartFile file, String path, String md5);
|
||||
|
||||
/**
|
||||
* 上传文件块
|
||||
* @param chunkInfo 文件块信息
|
||||
* @param path 上传路径
|
||||
* @return 是否上传成功
|
||||
*/
|
||||
Boolean uploadChunk(ChunkInfoDto chunkInfo, String path);
|
||||
|
||||
/**
|
||||
* 检查文件块信息
|
||||
* @param identifier 唯一标识
|
||||
* @param filename 文件名
|
||||
* @param path 上传文件夹路径
|
||||
* @return 检查结果
|
||||
*/
|
||||
ChunkResultDto checkChunk(String identifier, String filename, String path);
|
||||
|
||||
/**
|
||||
* 删除文件块
|
||||
* @param identifier 唯一标识
|
||||
* @param path 上传文件夹路径
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteChunk(String identifier, String path);
|
||||
|
||||
/**
|
||||
* 合并文件
|
||||
* @param filename 文件名
|
||||
* @param path 上传文件夹路径
|
||||
* @return 是否合并成功
|
||||
*/
|
||||
FileRecordDto mergeFile(String filename, String path);
|
||||
|
||||
List<FileInfoDto> getFolderInfo(String folderName);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package com.cxx.home.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.cxx.framework.web.CustomException;
|
||||
import com.cxx.home.constant.FileConstant;
|
||||
import com.cxx.home.dto.file.ChunkInfoDto;
|
||||
import com.cxx.home.dto.file.ChunkResultDto;
|
||||
import com.cxx.home.dto.file.FileInfoDto;
|
||||
import com.cxx.home.dto.file.FileRecordDto;
|
||||
import com.cxx.home.entity.FileRecord;
|
||||
import com.cxx.home.mapper.FileRecordMapper;
|
||||
import com.cxx.home.service.FileService;
|
||||
import com.cxx.home.util.FileUtils;
|
||||
import com.cxx.home.util.UploadFileUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileServiceImpl implements FileService {
|
||||
@Value("${file.path}")
|
||||
private String fileRootPath;
|
||||
|
||||
@Resource
|
||||
private FileRecordMapper fileRecordMapper;
|
||||
|
||||
@Override
|
||||
public FileRecordDto uploadFile(MultipartFile multipartFile, String path, String md5) {
|
||||
UploadFileUtil.checkDirIsExist(getFilePath(path));
|
||||
|
||||
String filename = multipartFile.getOriginalFilename();
|
||||
String newPath = path + File.separator + md5 + "." + FilenameUtils.getExtension(filename);
|
||||
File newFile = new File(getFilePath(newPath));
|
||||
|
||||
saveFile(multipartFile, newFile);
|
||||
|
||||
// 这里的url需要加上 WebMvcConfig 中设置的前缀
|
||||
String url = FileConstant.FILE_URL_PREFIX + File.separator + newPath;
|
||||
return getFileRecord(filename, md5, path, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean uploadChunk(ChunkInfoDto chunkInfo, String path) {
|
||||
MultipartFile file = chunkInfo.getMultipartFile();
|
||||
|
||||
try {
|
||||
// 1. 校验路径是否存在
|
||||
UploadFileUtil.checkDirIsExist(getFilePath(path));
|
||||
// 2. 获取文件块路径
|
||||
Path chunkPath = Paths.get(UploadFileUtil.generateChunkPath(getFilePath(path), chunkInfo));
|
||||
// 3. 将文件块写入指定路径
|
||||
Files.write(chunkPath, file.getBytes());
|
||||
} catch (IOException exception) {
|
||||
log.error("文件上传块失败: {}", exception.getMessage());
|
||||
throw new CustomException("文件上传块失败: " + exception.getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkResultDto checkChunk(String identifier, String filename, String path) {
|
||||
ChunkResultDto chunkResult = new ChunkResultDto();
|
||||
List<Integer> uploadedChunkList = new ArrayList<>();
|
||||
|
||||
String folder = getFilePath(path) + File.separator + identifier;
|
||||
String file = folder + File.separator + filename;
|
||||
|
||||
// 判断文件夹是否存在
|
||||
if (UploadFileUtil.fileExists(folder)) {
|
||||
// 先判断整个文件是否已经上传过了,如果是,则告诉前端跳过上传,实现秒传
|
||||
if (UploadFileUtil.fileExists(file)) {
|
||||
chunkResult.setSkipUpload(true);
|
||||
chunkResult.setUploadedChunkList(uploadedChunkList);
|
||||
log.info("完整文件已存在,直接跳过上传,实现秒传");
|
||||
} else {
|
||||
chunkResult.setSkipUpload(false);
|
||||
// 获取已经上传的文件块
|
||||
chunkResult.setUploadedChunkList(UploadFileUtil.getUploadedChunkList(folder, filename));
|
||||
}
|
||||
} else {
|
||||
chunkResult.setSkipUpload(false);
|
||||
chunkResult.setUploadedChunkList(uploadedChunkList);
|
||||
}
|
||||
|
||||
return chunkResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteChunk(String identifier, String path) {
|
||||
String folder = getFilePath(path) + File.separator + identifier;
|
||||
log.info("开始删除文件: " + folder);
|
||||
|
||||
// 判断文件夹是否存在
|
||||
if (UploadFileUtil.fileExists(folder)) {
|
||||
UploadFileUtil.deleteDirectory(folder);
|
||||
} else {
|
||||
throw new CustomException("文件: " + folder + "不存在");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileRecordDto mergeFile(String filename, String path) {
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||
String newFilename = uuid + "." + FilenameUtils.getExtension(filename);
|
||||
try {
|
||||
UploadFileUtil.mergeFile(newFilename, getFilePath(path));
|
||||
} catch (IOException exception) {
|
||||
throw new CustomException("合并文件: " + filename + " 失败");
|
||||
}
|
||||
|
||||
String newPath = path + File.separator + newFilename;
|
||||
String url = FileConstant.FILE_URL_PREFIX + File.separator + newPath;
|
||||
return getFileRecord(filename, uuid, path, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfoDto> getFolderInfo(String folderName) {
|
||||
File folder = new File(folderName);
|
||||
List<FileInfoDto> fileInfoList = new ArrayList<>();
|
||||
if (folder.exists() && folder.isDirectory()) {
|
||||
File[] files = folder.listFiles();
|
||||
if (files != null) {
|
||||
List<FileInfoDto> folderInfoList = new ArrayList<>();
|
||||
List<FileInfoDto> fileInfoSubList = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
FileInfoDto fileInfo = new FileInfoDto();
|
||||
fileInfo.setName(file.getName());
|
||||
if (file.isDirectory()) {
|
||||
fileInfo.setType("文件夹");
|
||||
fileInfo.setSize("-");
|
||||
folderInfoList.add(fileInfo);
|
||||
} else {
|
||||
fileInfo.setType(FileUtils.getFileType(file.getName()));
|
||||
fileInfo.setSize(FileUtils.formatSize(file.length()));
|
||||
fileInfoSubList.add(fileInfo);
|
||||
}
|
||||
fileInfo.setCreateDate(new Date(file.lastModified()));
|
||||
}
|
||||
fileInfoList.addAll(folderInfoList);
|
||||
fileInfoList.addAll(fileInfoSubList);
|
||||
}
|
||||
}
|
||||
return fileInfoList;
|
||||
}
|
||||
|
||||
private void saveFile(MultipartFile multipartFile, File file) {
|
||||
// 如果文件不存在
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
// 3. 如果不存在则创建文件
|
||||
multipartFile.transferTo(file);
|
||||
} catch (IOException e) {
|
||||
throw new CustomException("文件上传失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FileRecordDto getFileRecord(String filename, String md5, String path, String url) {
|
||||
FileRecord fileRecord = new FileRecord();
|
||||
fileRecord.setName(filename);
|
||||
fileRecord.setMd5(md5);
|
||||
fileRecord.setPath(path);
|
||||
fileRecord.setUrl(url);
|
||||
fileRecord.setId(saveDatabase(fileRecord, md5));
|
||||
|
||||
// 4. 返回文件信息
|
||||
FileRecordDto fileRecordDto = new FileRecordDto();
|
||||
BeanUtils.copyProperties(fileRecord, fileRecordDto);
|
||||
|
||||
return fileRecordDto;
|
||||
}
|
||||
|
||||
private Long saveDatabase(FileRecord fileRecord, String md5) {
|
||||
LambdaQueryWrapper<FileRecord> queryWrapper = Wrappers.lambdaQuery(FileRecord.class);
|
||||
FileRecord dbFileRecord = fileRecordMapper.selectOne(queryWrapper.eq(FileRecord::getMd5, md5));
|
||||
if (Objects.isNull(dbFileRecord)) {
|
||||
fileRecordMapper.insert(fileRecord);
|
||||
return fileRecord.getId();
|
||||
} else {
|
||||
return dbFileRecord.getId();
|
||||
}
|
||||
}
|
||||
|
||||
private String getFilePath(String path) {
|
||||
return fileRootPath + path;
|
||||
}
|
||||
}
|
||||
28
home-service/src/main/java/com/cxx/home/util/FileUtils.java
Normal file
28
home-service/src/main/java/com/cxx/home/util/FileUtils.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.cxx.home.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class FileUtils {
|
||||
public static String getFileType(String fileName) {
|
||||
int lastIndex = fileName.lastIndexOf('.');
|
||||
if (lastIndex != -1) {
|
||||
return fileName.substring(lastIndex + 1);
|
||||
}
|
||||
return "未知类型";
|
||||
}
|
||||
|
||||
public static String formatSize(long size) {
|
||||
if (size < 1024) {
|
||||
return size + " B";
|
||||
} else if (size < 1024 * 1024) {
|
||||
return String.format("%.2f KB", (double) size / 1024);
|
||||
} else if (size < 1024 * 1024 * 1024) {
|
||||
return String.format("%.2f MB", (double) size / (1024 * 1024));
|
||||
} else {
|
||||
return String.format("%.2f GB", (double) size / (1024 * 1024 * 1024));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
173
home-service/src/main/java/com/cxx/home/util/UploadFileUtil.java
Normal file
173
home-service/src/main/java/com/cxx/home/util/UploadFileUtil.java
Normal file
@@ -0,0 +1,173 @@
|
||||
package com.cxx.home.util;
|
||||
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import com.cxx.home.dto.file.ChunkInfoDto;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @Author: chenxiuxiang
|
||||
* @Date: 2023/7/24 14:49
|
||||
* @Description: 上传文件工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class UploadFileUtil {
|
||||
private static final String FILE_SEPARATOR = "_";
|
||||
|
||||
/**
|
||||
* 校验文件夹是否存在
|
||||
*
|
||||
* @param path 路径
|
||||
*/
|
||||
public static void checkDirIsExist(String path) {
|
||||
File dir = new File(path);
|
||||
if (!dir.exists() && !dir.isDirectory()) {
|
||||
boolean mkdir = dir.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件路径
|
||||
*
|
||||
* @param path 上传文件夹路径
|
||||
* @param chunkInfo 分片文件信息
|
||||
* @return 文件路径
|
||||
*/
|
||||
public static String generateChunkPath(String path, ChunkInfoDto chunkInfo) {
|
||||
return path + File.separator + chunkInfo.getFilename() + FILE_SEPARATOR + chunkInfo.getChunkNumber();
|
||||
}
|
||||
|
||||
public static List<Integer> getUploadedChunkList(String folder, String filename) {
|
||||
List<Integer> uploadedChunkList = new ArrayList<>();
|
||||
|
||||
// 获取文件夹下所有的文件
|
||||
try (Stream<Path> list = Files.list(Paths.get(folder))) {
|
||||
// 去除需要合并的文件
|
||||
list.filter(path -> !path.getFileName().toString().equals(filename))
|
||||
// 循环遍历文件 将已经上传的文件序号添加至列表中
|
||||
.forEach(path -> {
|
||||
String chunkPath = path.getFileName().toString();
|
||||
int index = chunkPath.lastIndexOf(FILE_SEPARATOR);
|
||||
uploadedChunkList.add(Integer.valueOf(chunkPath.substring(index + 1)));
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return uploadedChunkList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件合并
|
||||
*/
|
||||
public static void mergeFile(String filename, String path) throws IOException {
|
||||
// 判断文件是否存在
|
||||
String file = path + File.separator + filename;
|
||||
if (fileExists(file)) {
|
||||
deleteFile(file);
|
||||
}
|
||||
|
||||
// 不存在的话,进行合并
|
||||
Files.createFile(Paths.get(file));
|
||||
|
||||
// 获取文件夹下所有的文件
|
||||
try (Stream<Path> list = Files.list(Paths.get(path))) {
|
||||
// 保留后缀包含分隔符的
|
||||
list.filter(chunkPath -> FileNameUtil.getSuffix(chunkPath.getFileName().toString()).contains(FILE_SEPARATOR))
|
||||
// 按照文件名排序
|
||||
.sorted((o1, o2) -> {
|
||||
String p1 = o1.getFileName().toString();
|
||||
String p2 = o2.getFileName().toString();
|
||||
int i1 = p1.lastIndexOf(FILE_SEPARATOR);
|
||||
int i2 = p2.lastIndexOf(FILE_SEPARATOR);
|
||||
return Integer.valueOf(p1.substring(i1 + 1))
|
||||
.compareTo(Integer.valueOf(p2.substring(i2 + 1)));
|
||||
})
|
||||
// 循环写入到文件中
|
||||
.forEach(chunkPath -> {
|
||||
try {
|
||||
// 以追加的形式写入文件
|
||||
Files.write(Paths.get(file), Files.readAllBytes(chunkPath), StandardOpenOption.APPEND);
|
||||
// 合并后删除该块
|
||||
Files.delete(chunkPath);
|
||||
} catch (IOException exception) {
|
||||
log.error("写入文件失败: " + exception.getMessage());
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件的全路径名判断文件是否存在
|
||||
*/
|
||||
public static boolean fileExists(String file) {
|
||||
Path path = Paths.get(file);
|
||||
return Files.exists(path, LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除目录(文件夹)以及目录下的文件
|
||||
*
|
||||
* @param sPath 被删除目录的文件路径
|
||||
* @return 目录删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteDirectory(String sPath) {
|
||||
// 如果sPath不以文件分隔符结尾,自动添加文件分隔符
|
||||
if (!sPath.endsWith(File.separator)) {
|
||||
sPath = sPath + File.separator;
|
||||
}
|
||||
File dirFile = new File(sPath);
|
||||
// 如果dir对应的文件不存在,或者不是一个目录,则退出
|
||||
if (!dirFile.exists() || !dirFile.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean flag = true;
|
||||
// 删除文件夹下的所有文件(包括子目录)
|
||||
File[] files = dirFile.listFiles();
|
||||
for (File file : Objects.requireNonNull(files)) {
|
||||
// 删除子文件
|
||||
if (file.isFile()) {
|
||||
flag = deleteFile(file.getAbsolutePath());
|
||||
}
|
||||
// 删除子目录
|
||||
else {
|
||||
flag = deleteDirectory(file.getAbsolutePath());
|
||||
}
|
||||
if (!flag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("文件删除成功");
|
||||
// 删除当前目录
|
||||
return dirFile.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个文件
|
||||
*
|
||||
* @param sPath 被删除文件的文件名
|
||||
* @return 单个文件删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteFile(String sPath) {
|
||||
boolean flag = false;
|
||||
File file = new File(sPath);
|
||||
// 路径为文件且不为空则进行删除
|
||||
if (file.isFile() && file.exists()) {
|
||||
flag = file.delete();
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user