本文最后更新于 2024-09-30,文章内容可能已经过时。

大文件上传,通常使用文件分片形式进行文件上传,在获取到File 时,我们可以使用内置的api slice() 方法来进行文件分片,这个方法有两个参数,一个是起始位置到分片结束为止File.slice(0, 1000) 意思是从0开始截取到1000文件字节内容,最终返回一个blob对象{ size: 1048576, type: "" }!

blob对象 和 FiLe对象 一样通过body 形式发送给服务端进行存储,不过通过slice 分片方回的结果只是文件的基本信息(文件大小 文件类型 文件名...)真正的内容还需要通过 FileReader对象才能读取到文件内容!

定义input file

  <!-- 文件上传 -->
  <div class="upload-file">
    <input type="file" @change="handleFileChange" />
  </div>

监听 file 变化

async handleFileChange( e ){
  console.log( '选择的文件:', e.target.files[0] );
  console.time();
  let result = await cutFile(e.target.files[0])
  console.timeEnd();
  console.log( '切割后的文件:', result );
}

上面通过input[type="file"]获取文件File!

并且通过onchange监听获取文件的变化!

cutFile 函数来帮我们完成分片结果的处理!

创建cutFile分片函数

分片函数 参数,文件对象 file, 需要分片大小[ 比如一个文件总大小为100M ,分成5M进行存储 ]

chunkCount 分片大小(一共多少个分片): 文件大小 / 分片大小

/*
 *  将文件分片处理
 *  @param file 文件对象
 *  @param chunkSize 分片大小,默认 1M
 *  @returns {Array} 文件分片数组
 */
export const cutFile = async (file, chunkSize = 1024 * 1024) => {
  // 分片大小
  const chunkCount = Math.ceil(file.size / chunkSize);
  const chunks = [];
  for (let i = 0; i < chunkCount; i++) {
    const result = await createChunks(file, i, chunkSize);
    chunks.push(result);
  }
  return chunks;
};

createChunks 函数,用来创建分片!

参数: 文件 当前索引 分片大小 5M

/* 
  创建分片返回分片结果
*/
export const createChunks = (file, index, chunkSize) => {
  return new Promise((resolve, reject) => {
    // 开始分片索引
    const start = index * chunkSize;
    // 结束分片索引
    const end = start + chunkSize;
    const spark = new SparkMD5.ArrayBuffer();
    const reader = new FileReader();
    const blob = file.slice(start, end);
    reader.onload = (e) => {
      spark.append(e.target.result);
      resolve({
        start,
        end,
        index,
        hash: spark.end(),
        blob,
      });
    };
    reader.readAsArrayBuffer(blob);
  });
};

注意: 这里我们用到了SparkMD5 第三方库,用来帮助我们获取文件的hash值

hash 值有助于给分片文件分配唯一值,当页面刷新或网络中断时,通过此hash标识请求后端,返回中断前的上传结果,并继续上传!

注意: 计算hash值 比较耗费时间 消耗内存,处理此问题,需要通过多线程方式 Worker来处理!

渡一袁老师视频讲解