大文件分片上传

vue3+vite+typescript实现大文件前端部分 

<script setup lang="ts">
import SparkMD5 from 'spark-md5';

// 文件分片大小
const CHUNK_SIZE = 1024 * 1024;


// 假设的服务器端点,替换为实际的URL
const SERVER_ENDPOINT = 'https://server-endpoint/upload';
// 文件分片
const createChunks = (file: File) => {
  let cur = 0;
  let chunks: Blob[] = [];
  while (cur < file.size) {
    const blob = file.slice(cur, cur + CHUNK_SIZE);
    chunks.push(blob);
    cur += CHUNK_SIZE;
  }
  return chunks;
};

// 计算文件hash值
const calculateHash = (chunks: Blob[]) => {
  return new Promise((resolve, reject) => {
    const targets: Blob[] = []; // 所有参与计算的切片
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();

    chunks.forEach((chunk, index) => {
      if (index === 0 || index === chunks.length - 1) {
        targets.push(chunk);
      } else {
        targets.push(chunk.slice(0, 2)); // 前两个字节
        targets.push(chunk.slice(CHUNK_SIZE / 2 - 2, CHUNK_SIZE / 2 + 2)); // 中间两个字节
        targets.push(chunk.slice(CHUNK_SIZE - 2)); // 最后两个字节
      }
    });

    const readNext = () => {
      if (targets.length === 0) {
        resolve(spark.end(true));
        return;
      }
      const target = targets.shift();
      fileReader.readAsArrayBuffer(target);
    };

    fileReader.onload = () => {
      const result = fileReader.result as ArrayBuffer;
      spark.append(result);
      readNext();
    };

    fileReader.onerror = (error) => {
      reject(error);
    };

    readNext();
  });
};
// 单个分片上传函数
const uploadChunk = (chunk: Blob, index: number, totalChunks: number) => {
  const formData = new FormData();
  formData.append('file', chunk, `chunk_${index}_of_${totalChunks}`);
  formData.append('hash', ''); // 这里可以添加文件的总hash值,如果需要

  return fetch(SERVER_ENDPOINT, {
    method: 'POST',
    body: formData,
  }).then(response => {
    if (!response.ok) {
      throw new Error(`上传分片${index}失败`);
    }
    return response; // 这里可以根据服务器的响应来处理,例如返回上传成功的状态
  });
};

// 文件上传
const handleLoad = async (e: Event) => {
  const input = e.target as HTMLInputElement;
  const files = input.files;
  if (!files || files.length === 0) return;

  const file = files[0];
  console.log('文件:', file);

  // 文件分片
  const chunks = createChunks(file);
  console.log('分片数量:', chunks.length);

  // 计算文件hash值
  const hash = await calculateHash(chunks);
  console.log('文件Hash:', hash);

  console.log('文件Hash:', hash);

  try {
    // 上传所有分片
    const uploadPromises = chunks.map((chunk, index) => {
      return uploadChunk(chunk, index, chunks.length);
    });

    const uploadResults = await Promise.all(uploadPromises);
    console.log('所有分片上传完成:', uploadResults);

    // 这里可以添加上传完成后的逻辑,例如通知用户上传成功
  } catch (error) {
    console.error('文件上传失败:', error);
  }
};

</script>

<template>
<div>
  <input type="file" @change="handleLoad" />
</div>
</template>

<style scoped>
</style>

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值