共计 5521 个字符,预计需要花费 14 分钟才能阅读完成。
大文件分片下载
解决大文件上传超时问题,使用 Range 支持,对文件进行分片下载
步骤:
一、首先通过发送 0 - 1 长度去后端获取文件大小、名称等信息返回给前端
二、前端通过文件大小、分片大小计算出分片数据量,循环请求后端,分片获取文件数据,前端组合 Blob 数组数据,记录当前请求的索引和数据进行组合
三、全部异步请求完毕之后,对所有数据进行从大到小排序,从新生成一个新的 Blob, 一定要保证数组的顺序正确,不然打开文件会有异常
多线程异步下载
多线程下载 {{(fileSize/1073741824).toFixed(2) }} GB
{{downloadText}}
to 工具类
export default function to (promise) {
if (!promise || !Promise.prototype.isPrototypeOf(promise)) {
return new Promise((resolve, reject) => {
reject(new Error(`${promise}rn requires promises as the param"`))
}).catch((err) => {
return [err, null]
})
}
return promise.then(data => {
return [null, data]
}).catch(err => [err])
}
Java 后端代码
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Optional;
@RequestMapping("/download")
@RestController
@Api(tags = "文件下载")
@Slf4j
public class DownLoadController {
private final static String utf8 = "utf-8";
@GetMapping("/file")
public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setCharacterEncoding(utf8);
String drive = "F";
String fileName = "AdobeAcrobatProDC_setup.zip";
log.info(fileName, drive);
String pathAll = drive + ":" + fileName;
log.info("pathAll{}", pathAll);
OptionalString> pathFlag = Optional.ofNullable(pathAll);
File file = null;
if (pathFlag.isPresent()) {
file = new File(pathAll);
log.info("文件路径是{}", pathAll);
if (!file.exists()) {
log.warn("文件不存在");
return;
}
} else {
log.warn("请输入文件名!");
return;
}
InputStream is = null;
OutputStream os = null;
try {
long fSize = file.length();
response.setContentType("application/x-download");
String file_Name = URLEncoder.encode(file.getName(), "UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setHeader("Accept-Range", "bytes");
response.setHeader("fName", file_Name);
long pos = 0, last = fSize - 1, sum = 0;
if (null != request.getHeader("Range")) {
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
String numRange = request.getHeader("Range").replaceAll("bytes=", "");
String[] strRange = numRange.split("-");
if (strRange.length == 2) {
pos = Long.parseLong(strRange[0].trim());
last = Long.parseLong(strRange[1].trim());
if (last > fSize - 1) {
last = fSize - 1;
}
} else {
pos = Long.parseLong(numRange.replaceAll("-", "").trim());
}
}
long rangeLenght = last - pos + 1;
String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();
response.setHeader("Content-Range", contentRange);
os = new BufferedOutputStream(response.getOutputStream());
is = new BufferedInputStream(new FileInputStream(file));
is.skip(pos);
byte[] buffer = new byte[1024];
int lenght = 0;
while (sum rangeLenght) {
lenght = is.read(buffer, 0, (rangeLenght - sum) buffer.length ? (int) (rangeLenght - sum) : buffer.length);
sum = sum + lenght;
os.write(buffer, 0, lenght);
}
log.info("下载完成");
} finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
}
}
}
原文地址: Vue、Springboot 大文件分片下载、多线程下载
正文完