java:分块上传 和 合并分块

2021-05-28 02:01

阅读:763

标签:标识   获取   扩展名   mat   成功   while   formatter   files   last   

我们上传文件时,当文件比较大的时候,我们往往采用前端将大文件分割,分块多次上传给后端,全部上传成功再合并分块的方式上传。(这里仅介绍后端操作)

import com.sundear.model.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
* 文件处理工具类
*
* @author luc
* @date 2020/8/515:52
*/
@Slf4j
public class FileUtils {

/**
* 校验文件内容不为空
*
* @param file 文件对象
*/
public static void checkContent(MultipartFile file) {
//校验文件的内容
if (file.isEmpty()) {
throw new ServiceException(-1, "文件内容为空");
}
}

/**
* 判断文件是否在磁盘存在
*
* @param filePath 文件路径
* @return 存在=true;不存在=false
*/
public static boolean isExist(String filePath) {
return new File(filePath).exists();
}

/**
* 获取时间文件夹
*
* @param dateTime 时间
* @param pattern 格式
* @return 文件夹
*/
public static String dateTime2String(LocalDateTime dateTime, Object... pattern) {
if (dateTime == null) {
return "";
}
DateTimeFormatter df;
if (pattern != null && pattern.length > 0) {
df = DateTimeFormatter.ofPattern(pattern[0].toString());
} else {
df = DateTimeFormatter.ofPattern("yyyy/MM/dd/HH");
}
return dateTime.format(df);
}

/**
* 创建文件目录
*
* @param dirPath 文件地址
*/
@SuppressWarnings("all")
public static void createDir(String dirPath) {
//目录不存在,创建 分块文件目录
File dirFile = new File(dirPath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
}

/**
* 上传文件写入磁盘
*
* @param file 文件大小
* @param realPath 真是地址
* @return 是否写入成功
*/
@SuppressWarnings("all")
public static Boolean writeFile(MultipartFile file, String realPath) {
//在路径下创建文件
File dest = new File(realPath);
//将上传的文件保存
try {
if (!dest.exists()) {
//文件不存在,则创建
dest.createNewFile();
}
file.transferTo(dest);
return Boolean.TRUE;
} catch (IOException e) {
log.error(e.getMessage());
return Boolean.FALSE;
}
}

/**
* 删除文件夹及其目录下所有文件
*
* @param folderPath 文件夹地址
*/
@SuppressWarnings("all")
public static void delFolder(String folderPath) {
try {
//删除完里面所有内容
delAllFile(folderPath);
File myFilePath = new File(folderPath);
//删除空文件夹
myFilePath.delete();
} catch (Exception e) {
log.error(e.getMessage());
}
}

/**
* 删除指定文件夹下的所有文件
*
* @param path 路径
* @return true/false
*/
@SuppressWarnings("all")
public static void delAllFile(String path) {
File file = new File(path);
//文件夹不存在返回false\不是文件夹返回false
if (!file.exists() || !file.isDirectory()) {
return;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
//先删除文件夹里面的文件
delAllFile(path + "/" + tempList[i]);
//再删除空文件夹
delFolder(path + "/" + tempList[i]);
}
}
}

/**
* 获取文件扩展名
*
* @param file 文件
* @return 后缀
*/
public static String getFileSuffix(MultipartFile file) {
String fileName = file.getOriginalFilename();
if ((fileName != null) && (fileName.length() > 0)) {
int dot = fileName.lastIndexOf(‘.‘);
if ((dot > -1) && (dot return fileName.substring(dot);
}
}
assert fileName != null;
return fileName.toLowerCase();
}


/**
* 删除文件夹fromDir下的 howDays天前的文件
*
* @param fromDir 文件夹
* @param howDays 天数
* @return 数目
*/
@SuppressWarnings("all")
public static Integer clearFileCache(String fromDir, int howDays) {
File srcDir = new File(fromDir);
if (!srcDir.exists()) {
return 0;
}
File[] files = srcDir.listFiles();
if (files == null || files.length return 0;
}
// 删除文件总数
int delTotal = 0;
Date today = new Date();
for (File file : files) {
if (file.isFile()) {
try {
long time = file.lastModified();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
Date lastModified = cal.getTime();
//(int)(today.getTime() - lastModified.getTime())/86400000;
long days = getDistDates(today, lastModified);
// 删除多少天前之前文件
if (days >= howDays) {
file.delete();
delTotal++;
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
return delTotal;
}

/**
* 获取两个时间之间的 天数
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 天数
*/
public static long getDistDates(Date startDate, Date endDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
long timeStart = calendar.getTimeInMillis();
calendar.setTime(endDate);
long timeEnd = calendar.getTimeInMillis();
return Math.abs((timeEnd - timeStart)) / (1000 * 60 * 60 * 24);
}
}

开始分片上传

/**
* 分片上传
*
* @param file 文件对象
* @param req 唯一标识+类型分组
* @param partNum 分片号
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void uploadPart(MultipartFile file, ValidReq req, Integer partNum) {
String fileType = req.getFileType();
String fileMd5 = req.getFileMd5();
String clientId = req.getClientId();
//校验文件内容不为空
FileUtils.checkContent(file);
//获取分片号
partNum = (partNum == null) ? 0 : partNum;
//服务器上传路径
String comPath = properties.comPath();
//分块存储目录
String partPath = String.join(FileConstant.SEPARATOR, comPath, fileMd5).replaceAll("//+", "/");
//当前分块全路径: 服务器路径/文件md5签名/分片文件
String partFilePath = String.join(FileConstant.SEPARATOR, partPath, String.valueOf(partNum));

//校验分片是否上传
boolean isUpload = FileUtils.isExist(partFilePath);
if (!isUpload) {
//分片目录不存在,创建 分块文件目录
FileUtils.createDir(partPath);
//分片文件写入磁盘
Boolean isSuccess = FileUtils.writeFile(file, partFilePath);
if (partNum == 0) {
if (isSuccess) {
//上传第一片分块时,写入数据库
String suffix = FileUtils.getFileSuffix(file);
String fileId = IdWorker.getIdWorker().nextIdStr();
UploadFile uploadFile = new UploadFile();
uploadFile.setFileId(fileId);
uploadFile.setFileMd5(fileMd5);
uploadFile.setFileName(file.getOriginalFilename());
uploadFile.setFileType(fileType);
Byte status = FileStatusEnum.UPLOADING.getCode();
uploadFile.setFileStatus(status);
uploadFile.setClientId(clientId);
uploadFile.setFileSuffix(suffix);
uploadFileService.insert(uploadFile);
log.info("上传第一个分片文件,生成文件上传记录,文件id: " + fileId);
} else {
log.info("上传第一个分片文件失败");
}
} else {
log.info("上传第" + partNum + "个分片成功");
}
}
}

/**
* 服务器文件地址
*/
public String comPath(){
return String.join(FileConstant.SEPARATOR, this.uploadPath, this.filePath).replaceAll("//+", "/");
}

合并分片

/**
* 分片合并完成上传
*
* @param req 唯一标识+类型分组
* @param partTotal 分片数
* @return 文件记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public UploadFile uploadFinish(ValidReq req, Integer partTotal) {
String fileType = req.getFileType();
String fileMd5 = req.getFileMd5();
//获取文件上传记录数据
UploadFile uploadFile = uploadFileService.getByFileMd5(req);

if (uploadFile == null || StringUtils.isBlank(uploadFile.getFileId())) {
throw new ServiceException(-1, "分片未正确上传");
}
if (partTotal == null || partTotal == 0) {
throw new ServiceException(-1, "分片总数不能为空");
}
//上传路径
String comPath = properties.comPath();
//相对路径
String relativePath = String.join(FileConstant.SEPARATOR, fileType, FileUtils.dateTime2String(LocalDateTime.now())).replaceAll("//+", "/");
//xxx/files/2020/08/11/13
String dirPath = String.join(FileConstant.SEPARATOR, comPath, relativePath).replaceAll("//+", "/");
//最终文件路径,不存在的话生成文件目录
FileUtils.createDir(dirPath);
//文件真实路径
String realPath = String.join(FileConstant.SEPARATOR, dirPath, uploadFile.getFileId() + uploadFile.getFileSuffix()).replaceAll("//+", "/");

//分块存储目录
String partPath = String.join(FileConstant.SEPARATOR, comPath, fileMd5).replaceAll("//+", "/");

///合成后的文件流
try (FileOutputStream fileOutputStream = new FileOutputStream(realPath)) {
byte[] buf = new byte[1024];
for (long i = 0; i //当前分块全路径: 服务器路径/文件md5签名/分片文件
String partFilePath = String.join(FileConstant.SEPARATOR, partPath, String.valueOf(i));
//获取分块文件
File file = new File(partFilePath);
//获取文件流
InputStream inputStream = new FileInputStream(file);
int len;
while ((len = inputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, len);
}
inputStream.close();
}
//删除md5目录,及临时文件
FileUtils.delFolder(partPath);
//文件大小设置
File finalFile = new File(realPath);
String size = String.valueOf(finalFile.length());

uploadFile.setFileSize(size);
uploadFile.setFilePath(relativePath);
uploadFile.setFileStatus(FileStatusEnum.PASS.getCode());
uploadFileService.update(uploadFile);
} catch (Exception e) {
log.error(e.getMessage());
throw new ServiceException(-1, "文件合并异常");
}
return uploadFile;
}


java:分块上传 和 合并分块

标签:标识   获取   扩展名   mat   成功   while   formatter   files   last   

原文地址:https://www.cnblogs.com/yxj808/p/14808835.html


评论


亲,登录后才可以留言!