Case
- 10MB file splite into 1M * 10 files
- FileId, TotalSize, PartNum, PartSeq, PartSize
- eg. A, 10MB, 10, 01, 1MB
Request
- FileId, TotalSize, PartNum, PartSeq, PartSize
- MultipartFile
Server
- Find the file by FileId, If not Found, Create one
- Use RandomAccessFile to Write byte at any given position
- Position -> (partSeq - 1) * PartSize
- count -> received part nums
- if partNums = partNum -> finished
@RestController
public class FileController {
// 存放文件的临时目录
private static final String DATA_DIR = System.getProperty("user.dir") + "/temp/";
// 文件MD5的缓存容器
private static final ConcurrentMap<String, File> MD5_CACHE = new ConcurrentHashMap<>();
/**
* 大文件分片上传
* @param name 文件名
* @param md5 文件MD5值
* @param size 文件大小
* @param chunks 总的分片数
* @param chunk 当前分片数
* @param multipartFile 分片流
* @throws IOException
*/
@PostMapping("/chunk/upload")
public void chunkUpload(String name,
String md5,
Long size,
Integer chunks,
Integer chunk,
@RequestParam("file") MultipartFile multipartFile) throws IOException {
// 是否生成了文件???
File targetFile = MD5_CACHE.get(md5);
if (targetFile == null) {
// 没有生成的话就生成一个新的文件,没有做并发控制,多线程上传会出问题
targetFile = new File(DATA_DIR, UUID.randomUUID().toString(true) + "." + FileNameUtil.extName(name));
targetFile.getParentFile().mkdirs();
MD5_CACHE.put(md5, targetFile);
}
// 可以对文件的任意位置进行读写
RandomAccessFile accessFile = new RandomAccessFile(targetFile, "rw");
boolean finished = chunk == chunks;//此处判断应该使用该ID已接受的包的数量
if (finished) {
// 移动指针到指定位置
accessFile.seek(size - multipartFile.getSize());
}else {
accessFile.seek((chunk - 1) * multipartFile.getSize());
}
// 写入分片的数据
accessFile.write(multipartFile.getBytes());
accessFile.close();
if (finished) {
System.out.println("success.");
// 上传成功
MD5_CACHE.remove(md5);
}
}
}
本文由 Ivan Dong 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 13, 2023 at 09:59 am