upload

大文件如何实现断点续传实现大文件的断点续传,可以通过以下步骤实现。这通常包括文件切片上传控制服务端合并等过程。以下是具体的实现步骤:


1. 实现原理

断点续传的核心思想是将文件切分为多个小块(chunk),分块上传,并记录每块的上传状态。如果上传中断,重新上传时可以从未完成的块继续上传,而不是重新上传整个文件。


2. 前端实现流程

(1) 文件切片

通过 FileBlob 对象,将大文件切分成固定大小的块。

function sliceFile(file, chunkSize = 2 * 1024 * 1024) { // 每块 2MB
  const chunks = [];
  let current = 0;

  while (current < file.size) {
    chunks.push(file.slice(current, current + chunkSize));
    current += chunkSize;
  }

  return chunks;
}

(2) 计算文件的唯一标识

通过文件的内容生成一个唯一标识(如 hash),确保服务端可以识别文件和对应的块。

async function calculateHash(file) {
  const sparkMD5 = new SparkMD5.ArrayBuffer(); // 使用 SparkMD5 或其他库
  const chunkSize = 2 * 1024 * 1024; // 2MB
  const chunks = sliceFile(file, chunkSize);
  for (const chunk of chunks) {
    const buffer = await chunk.arrayBuffer();
    sparkMD5.append(buffer);
  }
  return sparkMD5.end();
}

(3) 分块上传

使用 FormData 将每个块上传到服务器。

async function uploadChunk(file, chunk, index, hash) {
  const formData = new FormData();
  formData.append("file", chunk);
  formData.append("filename", file.name);
  formData.append("index", index);
  formData.append("hash", hash);

  return fetch("/upload", {
    method: "POST",
    body: formData,
  });
}

(4) 检查已上传的块

在上传前,向服务器发送请求,获取已上传的块信息,避免重复上传。

async function getUploadedChunks(hash) {
  const response = await fetch(`/upload/status?hash=${hash}`);
  return response.json(); // 返回已上传的块列表
}

(5) 控制上传逻辑

利用 Promise.allasync/await 控制上传过程,并记录每块的上传状态。

async function uploadFile(file) {
  const hash = await calculateHash(file);
  const chunks = sliceFile(file);
  const uploadedChunks = await getUploadedChunks(hash);

  for (let i = 0; i < chunks.length; i++) {
    if (uploadedChunks.includes(i)) {
      console.log(`Chunk ${i} already uploaded`);
      continue;
    }

    await uploadChunk(file, chunks[i], i, hash);
    console.log(`Chunk ${i} uploaded`);
  }

  // 通知服务端合并文件
  await fetch(`/upload/merge`, {
    method: "POST",
    body: JSON.stringify({ hash, filename: file.name }),
    headers: { "Content-Type": "application/json" },
  });
}

3. 服务端实现流程

(1) 接收文件块

  • 使用 multipart/form-data 接收上传的文件块。
  • 将每个文件块临时存储到服务器,命名时附带块索引和文件的 hash

(2) 记录上传状态

  • 在服务器端记录已上传的块信息(如在数据库或缓存中存储)。
  • 响应客户端的上传状态请求。

(3) 文件合并

  • 在接收到所有文件块后,将它们按顺序合并成完整文件。
  • 删除临时块文件,释放存储空间。

4. 断点续传的核心技术

文件切片

利用前端 File.slice 方法,将文件分成多个小块,便于上传和重传。

文件校验

通过 hashMD5 校验,确保上传过程中数据完整。

状态记录

  • 客户端记录上传进度,方便中断后重新开始。
  • 服务端记录已上传块,避免重复上传。

并发上传

使用多线程并发上传多个文件块,提高上传速度。


5. 示例架构

前端

  • 使用 HTML5 提供的 File API 实现文件读取和切片。
  • 使用 fetchaxios 实现 HTTP 请求。

服务端

  • 使用 Node.jsExpress 或其他框架处理文件块上传。
  • 存储已上传的文件块和状态,提供文件合并接口。

6. 常见优化

  1. 并发上传控制:使用限制并发数量的工具(如 Promise.allSettled)。
  2. 重试机制:在块上传失败时进行自动重试。
  3. 前端暂停/恢复:提供上传的暂停和恢复功能。
  4. 服务端资源清理:定期清理超时未完成的临时文件。

通过以上方法,可以实现高效、可靠的大文件断点续传。

苏ICP备2025153828号