大文件上传-随记

67 阅读2分钟

某站进行大文件上传时查看网络我们会发现会不断生成ajax请求这是由于:文件一旦过大,一次发送,时间将会很长,如果发送过程发生错误,我们很难承受后果。所以我们上传大文件的时候,往往会切片处理

1、对文件进行切片

file和blob只是保存数据的 size \ type \ name 这些数据

所以切片上传的是数组运算,所以很快,想要读到数据,使用fileReader

2、如果我们上传了一部分的时候,发生了断网需要重新传输,这时就需要断点续传

通过一次ajax请求,客户端从服务器获取到这个文件还需要传递哪些分片,那么“这个文件”如何描述呢?

能够唯一表示文件切片的----hash(md5) --------- hash将任何数据 ->固定长度字符串

现在我们来实现一下文件数据与hash的转化,当然这里不推荐使用一次性将所有数据转换成hash,我们采用切片、增量算法实现转化,这里我们定义一个方法接收数据块,并且引入三方库spark-md5实现hash转化

  <!DOCTYPE html>
  <html>
  <head>
    <title>大文件分片上传Demo</title>
    <!-- 引入MD5计算库 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.2/spark-md5.min.js"></script>
  </head>
  <body>
    <input type="file" id="fileInput" /><script>
      /* 1. 监听文件选择事件 */
      document.querySelector('input').onchange = async function(e) {
        const file = e.target.files[0];
        if (!file) return;
  ​
        /* 2. 文件切片处理 */
        const chunks = sliceFile(file, 10 * 1024); // 每片10KB,根据网络来定
        
        /* 3. 计算文件唯一hash*/
        const fileHash = await computeHash(chunks); //异步执行
        console.log('最终文件hash:', fileHash);
  ​
      };
  ​
      /* 文件切片函数 */
      function sliceFile(file, chunkSize) {
        const chunks = [];
        // 用slice方法切割文件
        for (let i = 0; i < file.size; i += chunkSize) {
          chunks.push(file.slice(i, i + chunkSize));
        }
        return chunks;
      }
  ​
      /* 增量计算文件hash */
      function computeHash(chunks) {
        return new Promise(resolve => {
          const spark = new SparkMD5(); // 创建MD5计算器
          let processed = 0; // 已处理分片计数
  ​
          function processChunk(index) {
            // 所有分片处理完成
            if (index >= chunks.length) {
              resolve(spark.end()); // 返回最终hash
              return;
            }
  ​
            const reader = new FileReader();
            // 分片读取完成时
            reader.onload = e => {
              spark.append(e.target.result); // 增量更新hash
              processed++;
              processChunk(processed); // 处理下一分片
            };
            
            // 读取当前分片
            reader.readAsArrayBuffer(chunks[index]);
          }
  ​
          processChunk(0); // 从第一个分片开始
        });
      }
    </script>
  </body>
  </html>

也是实现了将文件切片转换成hash值,后续将hash值传给后端geigei处理吧

1751987275476.png

那么后续我们也可以直接根据后端返回的hash存储与文件数据的对应关系找到对应的文件哩:

文件存储流程:

1751987674399.png

文件检索流程:

1751987700081.png