文件的分片下载顾名思义就是将文件分成一片一片,每次请求只下载一片,最后将文件进行整合下载,目的是为了防止文件大的情况,出现系统崩溃
SpringBoot后端实现文件的分片
@GetMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fileName = "1325.MP4";
// String fileName = "SanGeng_Security_Project.zip";
String filePath = "/Users/tianzhuang/Desktop/work/" + fileName;
File file = new File(filePath);
long fileSize = file.length();
// Set content type and headers
response.setContentType("application/octect-stream;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setHeader("Accept-Ranges", "bytes");
// Check if range header is present
String rangeHeader = request.getHeader("Range");
if (rangeHeader == null) {
// Download entire file
response.setHeader("Content-Length", String.valueOf(fileSize));
InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
in.close();
out.close();
} else {
// Download partial content
long start = 0;
long end = fileSize - 1;
String[] range = rangeHeader.split("=")[1].split("-");
if (range.length == 1) {
start = Long.parseLong(range[0]);
end = fileSize - 1;
} else {
start = Long.parseLong(range[0]);
end = Long.parseLong(range[1]);
}
long contentLength = end - start + 1;
// 返回头里存放每次读取的开始和结束字节
response.setHeader("Content-Length", String.valueOf(contentLength));
response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
// 跳到第start字节
in.skip(start);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
long bytesWritten = 0;
while ((bytesRead = in.read(buffer)) != -1) {
if (bytesWritten + bytesRead > contentLength) {
out.write(buffer, 0, (int) (contentLength - bytesWritten));
break;
} else {
out.write(buffer, 0, bytesRead);
bytesWritten += bytesRead;
}
}
in.close();
out.close();
}
}
Vue前端代码实现
<template>
<div>
<button @click="downloadFile">Download File</button>
</div>
</template>
<script>
import axios from 'axios';
export default {
methods: {
async downloadFile() {
const url = 'api/download';
const chunkSize = 1024 * 1024 * 5; // 1MB
let start = 0;
let end = chunkSize - 1;
let fileSize = 0;
let chunks = [];
// Get file size
const response = await axios.head(url);
fileSize = response.headers['content-length'];
console.warn(`1111====${fileSize}`);
// Calculate number of chunks
const numChunks = Math.ceil(fileSize / chunkSize);
console.warn(`222====${numChunks}`);
if (fileSize < chunkSize) {
end = fileSize - 1;
}
// Download chunks
for (let i = 0; i < numChunks; i++) {
const range = `bytes=${start}-${end}`;
console.warn(`333====${range}`);
const config = {
headers: {
Range: range
},
responseType: 'arraybuffer'
};
const response = await axios.get(url, config);
chunks.push(response.data);
start = end + 1;
end = Math.min(end + chunkSize, fileSize - 1);
// console.warn(`444===${start}===${end}`)
}
// Combine chunks into a single file
const blob = new Blob(chunks);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = '1325.MP4';
link.click();
},
downloadFile2() {
}
}
};
</script>
下边是效果
勿喷,希望大佬多多指教