原生分片文件上传、合并的具体步骤

2024-06-19 22:20

本文主要是介绍原生分片文件上传、合并的具体步骤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前端是把文件分片传来的,获得第一片文件的时候要进行下特殊的判断:数据库中是否已经有了该文件(通过文件的MD5值进行查询),如果有的话就重命名,并且实现秒传。
//如果上传的是第一个分片
if (chunkIndex == 0) {
​//封装一个查询,查询数据库中是否已经有FileInfoQuery infoQuery = new FileInfoQuery();infoQuery.setFileMd5(fileMd5);//设置md5infoQuery.setStatus(FileStatus.USING.getStatus()); //必须是usingList<FileInfo> dbFileList = fileInfoMapper.selectList(infoQuery); //查询这个分片是否上传了
​if (!dbFileList.isEmpty()) { //已经有了,就需要重新命名FileInfo fileInfo = dbFileList.get(0);if (fileInfo.getFileSize() < 0) //TODO:到了后面修改,判断现有空间是否可以装下,此分片throw new BusinessException(ResponseCodeEnum.CODE_904);
​/*封装信息*/fileInfo.setFileId(fileId);fileInfo.setFilePid(filePid);fileInfo.setUserId(userInfo.getUserId());fileInfo.setLastUpdateTime(LocalDateTime.now());fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());fileInfo.setStatus(FileStatus.USING.getStatus());fileInfo.setFileMd5(fileMd5);
​//进行重新命名操作fileName = autoRename(filePid, userInfo.getUserId(), fileName);fileInfo.setFileName(fileName);
​//更新数据信息fileInfoMapper.insert(fileInfo);
​resultDTO.setStatus(UploadStatus.UPLOAD_SECONDS.getStatus());  //设置秒传
​//更新用户使用空间updateUserSpace(userInfo, fileInfo.getFileSize());return resultDTO;}
}

除了最后一个文件片段,其余的片段都要获取chunkIndex, 放到临时的目录下面去,返回信息到前端,以便前端可以继续上传其余片段。

//判断是不是上传最后一次切片
if (chunkIndex < chunks - 1) {resultDTO.setStatus(UploadStatus.UPLOADING.getStatus());//TODO:更新Redis中的信息return resultDTO;
}

到了最后一个片段,就需要获得文件的一些信息:后缀名、文件类型的枚举、不重复的文件名称等,封装好对应的信息,放到数据库中去。

String suffix = StringTools.getFileSuffix(fileName);
//真实的文件名
String realFileName = currentUserFolderName + suffix;
​
// 文件类型的枚举
FileTypeEnums fileTypeEnums = FileTypeEnums.getFileTypeBySuffix(suffix);
​
//自动重命名
fileName = autoRename(filePid,userInfo.getUserId(),fileName);
​
​
FileInfo fileInfo = new FileInfo();  //Entity
fileInfo.setFileId(fileId);
fileInfo.setUserId(userInfo.getUserId());
fileInfo.setFileName(fileName);
fileInfo.setFileMd5(fileMd5);
fileInfo.setFileName(getYearAndMouth() + "/" + realFileName );
fileInfo.setCreateTime(LocalDateTime.now());  //设置时间
fileInfo.setLastUpdateTime(LocalDateTime.now()); //最后一次更新时间
fileInfo.setFileCategory(fileTypeEnums.getType());  //设置种类
fileInfo.setFileType(fileTypeEnums.getType());   //设置种类
​
fileInfo.setStatus(FileStatus.TRANSFER.getStatus());  //设置转码中
fileInfo.setFolderType(FileFolderTypeEnums.FILE.getType());  //文件
fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());  //使用中
​
​
//插入到数据库中去
this.fileInfoMapper.insert(fileInfo);
​
//TODO:更新redis中容量,Mysql中数据的占用
resultDTO.setStatus(UploadStatus.UPLOAD_FINISH.getStatus());  //设置文件上传完毕

上传完成所有的文件片段后,使用异步的方式,完成文件片段的合成。

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {@Overridepublic void afterCommit() {fileInfoService.transferFile(fileInfo.getFileId(),userInfo);  //异步请求}
});

这里的fileInfoService 也得在fileInfoServiceImpl中注入,而且要加上@Lazy,避免循环引用。

在transferFile中,需要根据传入的信息,进行前面insert数据的查询,如果不存在就直接返回,因为合并的文件不存在。

if(fileInfos == null || fileInfos.size() == 0 ||! FileStatus.TRANSFER.getStatus().equals(fileInfos.get(0).getStatus())){  //文件不是转码中或者文件为空return;
}

拼装临时目录、真实文件路径和真实文件名称。

//临时目录
String tempFolderName = appconfiguration.getProjectFolder() + Constants.FILE_FOLDER_TEMP;
String currentUserFolderName = sessionWebDTO.getUserId() + fileId;
File fileFolder = new File(tempFolderName + currentUserFolderName);
​
String fileSuffix = StringTools.getFileSuffix(fileInfo.getFileName());  //获得文件后缀
String date = getYearAndMouth();  //就是为了获得目标目录
String targetFolderName = appconfiguration.getProjectFolder() + Constants.FILE_FOLDER_FILE; //真实目录

获得上一步存入的临时文件夹。

File targetFolder = new File(targetFolderName + "/" + date);

调用union方法,合并文件。

union(fileFolder.getPath(),targetFilePath,fileInfo.getFileName(),true);

在union中进行文件的合并,根据文件路径,获得对应的临时文件夹,使用writeFile(RandomAccessFile)写入的最最终的文件,使用readFile(RandomAccessFile)读入每个临时文件,放到最终的文件中去。

try{writeFile = new RandomAccessFile(targetFile,"rw");byte[] b = new byte[1024 * 10];for(int i = 0;i < fileList.length; i++){int len = -1;File chunkFile = new File(dirPath + "/" + i);  //分片文件RandomAccessFile readFile = null;try{readFile = new RandomAccessFile(chunkFile,"r");  //读取while((len = readFile.read(b))!= -1){writeFile.write(b,0,len);}}catch (Exception e){System.err.printf("-----------------------文件读取错误:%s :-------------------------",e.getMessage());throw new BusinessException("文件读取失败!");}finally {readFile.close();}}
}catch(Exception e){log.error("合并文件失败 :{}",fileName);throw new BusinessException("上传文件失败 !");
}finally {if(writeFile != null){try{writeFile.close();  //关闭对应的文件流}catch (IOException e){e.printStackTrace();}}if(delSource && dir.exists()){try {FileUtils.deleteDirectory(dir);} catch (IOException e) {e.printStackTrace();}}
}

最后关闭各种流,更新file_info中的文件大小、状态信息。

finally {
​//更新转码状态FileInfoUpdateDto updateInfo = new FileInfoUpdateDto();
​updateInfo.setFileSize(new File(targetFilePath).length());   //获得目标文件的大小updateInfo.setFileCover(cover);updateInfo.setStatus(transferSuccess ? FileStatus.USING.getStatus() : FileStatus.TRANSFER_FAIL.getStatus() );updateInfo.setFileId(fileId);updateInfo.setUserId(sessionWebDTO.getUserId());updateInfo.setNewValue(updateInfo.getStatus());updateInfo.setOldStatus(FileStatus.TRANSFER.getStatus());
​//封装信息fileInfoMapper.updateFileStatusWithOldStatus(updateInfo);
}

这篇关于原生分片文件上传、合并的具体步骤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1076309

相关文章

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

MySQL进行分片合并的实现步骤

《MySQL进行分片合并的实现步骤》分片合并是指在分布式数据库系统中,将不同分片上的查询结果进行整合,以获得完整的查询结果,下面就来具体介绍一下,感兴趣的可以了解一下... 目录环境准备项目依赖数据源配置分片上下文分片查询和合并代码实现1. 查询单条记录2. 跨分片查询和合并测试结论分片合并(Shardin

基于Python实现进阶版PDF合并/拆分工具

《基于Python实现进阶版PDF合并/拆分工具》在数字化时代,PDF文件已成为日常工作和学习中不可或缺的一部分,本文将详细介绍一款简单易用的PDF工具,帮助用户轻松完成PDF文件的合并与拆分操作... 目录工具概述环境准备界面说明合并PDF文件拆分PDF文件高级技巧常见问题完整源代码总结在数字化时代,PD

pandas数据的合并concat()和merge()方式

《pandas数据的合并concat()和merge()方式》Pandas中concat沿轴合并数据框(行或列),merge基于键连接(内/外/左/右),concat用于纵向或横向拼接,merge用于... 目录concat() 轴向连接合并(1) join='outer',axis=0(2)join='o

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建