Utils

Large File Upload

参考

文章:https://juejin.cn/post/6844904046436843527 源代码:https://github.com/yeyan1996/file-upload/blob/master/src/App.vue

大文件分片上传、断点续传

  • 分片上传、断点续传
  • 将 10G 的文件切成十个 100M 的文件,再将 100M 的小文件切成 10M 的文件
  • 此时有 100 个 10M 的小文件,计算这 100 个小文件的 hash
  • 上传切片,一次 10M
  • 如果网络中断,可以通过文件的 hash 来判断哪些文件没传,将没上传的文件继续上传
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/spark-md5/3.0.2/spark-md5.min.js"></script>
  </head>
  <body>
    <input type="file" />

    <script>
      // 文件切片
      const createChunks = (file, chunkSize) => {
        const result = [];
        for (let i = 0; i < file.size; i += chunkSize) {
          result.push(file.slice(i, i + chunkSize));
        }
        return result;
      };

      // 使用增量算法 计算文件的hash
      const hash = (chunks) => {
        return new Promise((resolve) => {
          const spark = new SparkMD5();
          const _read = (i) => {
            // 读取文件完成
            if (i >= chunks.length) {
              resolve(spark.end());
              return;
            }
            const blob = chunks[i];
            const reader = new FileReader();
            reader.onload = (e) => {
              const bytes = e.target.result; //读取到的字节数组
              spark.append(bytes); //增量计算hash
              _read(i + 1);
            };
            reader.readAsArrayBuffer(blob);
          };
          _read(0);
        });
      };

      const input = document.querySelector("input");
      input.onchange = async (e) => {
        // 拿到File对象
        const file = e.target.files[0];
        if (!file) return;

        // 拿到分片结果 利用分片计算就是为了减少内存占用,否则直接计算一整个文件的hash可能内存不够
        const chunks = createChunks(file, 10 * 1024 * 1024);

        // 拿到file文件的hash结果
        const result = await hash(chunks);
      };
    </script>
  </body>
</html>