如果文件过大,可以在前端切成多片,然后一片一片往后端传,这里我们可以用for循环结合await来可实现。
// 模拟异步获取数据的函数
async function fetchData(index) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`数据 ${index} 加载完成`);
resolve(`数据 ${index}`);
}, 1000); // 模拟网络延迟
});
}
// 使用for循环结合await
async function loadAllData() {
const totalItems = 5; // 假设我们需要加载5个数据项
const results = [];
for (let i = 0; i < totalItems; i++) {
const data = await fetchData(i); // 等待每个数据项加载完成
results.push(data);
}
console.log('所有数据加载完成:', results);
}
// 调用函数
loadAllData();
上传的文件,需要加一个hash凭证,如果上传过的文件,下次就直接返回了,不用再分片了。
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import SparkMD5 from 'spark-md5';
import { NzMessageService } from 'ng-zorro-antd/message';
import { environment } from 'src/environments/environment';
import { firstValueFrom } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class FileUploadService {
progress: number = 0;
constructor(private message: NzMessageService, private http: HttpClient) {}
calculateFileMD5(file, chunkSize = 2 * 1024 * 1024) {
// 默认分块大小为2MB
return new Promise((resolve, reject) => {
const spark = new SparkMD5.ArrayBuffer(); // 使用SparkMD5库,因为它支持增量计算
const fileReader = new FileReader();
let offset = 0; // 当前读取的文件偏移量
fileReader.onload = function (e: any) {
spark.append(e.target.result); // 增量添加文件内容到MD5计算器
offset += e.target.result.byteLength;
if (offset < file.size) {
// 如果还有剩余部分,继续读取下一块
loadNextChunk();
} else {
// 所有块都已读取完毕,完成MD5计算
resolve(spark.end());
}
};
fileReader.onerror = function (e: any) {
reject(new Error('Failed to read file for MD5 calculation: ' + e.target.error));
};
function loadNextChunk() {
const slice = file.slice(offset, offset + chunkSize);
fileReader.readAsArrayBuffer(slice);
}
// 开始读取第一块
loadNextChunk();
});
}
async checkfileMD5(filemd5){
const baseUrl = environment.apiUrl;
const url = baseUrl + `/api/file/query`;
const result = await firstValueFrom(this.http.get(url, { params: { checksum: filemd5 } }));
return result;
}
async uploadFile(file: any) {
// this.isUploading = true;
this.progress = 0;
if (file) {
var chunkSize = 1024 * 1024; // 每片1MB
var totalChunks = Math.ceil(file.size / chunkSize);
const fileMD5 = await this.calculateFileMD5(file);
console.log('filemd5>>>>', fileMD5);
//先检查fileMD5的值,如果上传过就不需要分片过程了
const checkRes:any = await this.checkfileMD5(fileMD5);
if (
checkRes &&
checkRes.code === 0 &&
checkRes.data &&
Array.isArray(checkRes.data.items) &&
checkRes.data.items[0]
) {
const fileMsg = checkRes.data.items[0];
if (fileMsg.file_status === 3) { //如果查询到md5值,就直接返回结果,不走分片
this.progress = 100;
return { code: 0, data: fileMsg };
}
}
const baseUrl = environment.apiUrl;
const url = baseUrl + `/api/file/upload_chunk`;
let result;
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
var start = currentChunk * chunkSize;
var end = Math.min(start + chunkSize, file.size);
var chunk = file.slice(start, end);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunk_index', '' + currentChunk);
formData.append('total_chunks', '' + totalChunks);
formData.append('checksum', '' + fileMD5);
formData.append('filename', file.name);
formData.append('total_size', file.size);
console.log('progress', currentChunk, totalChunks, this.progress);
result = await firstValueFrom(this.http.post(url, formData));
this.progress = ((currentChunk + 1) / totalChunks) * 100;
console.log(this.progress, currentChunk, result);
}
return result;
}
}
}