angular大文件分片上传

如果文件过大,可以在前端切成多片,然后一片一片往后端传,这里我们可以用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;
    }
  }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。