说说文件分片上传的事儿(s3)

2,354 阅读2分钟

原理

将文件的二进制流切割成指定大小的块儿,对每一块儿加唯一标识,方便文件按顺序合成

步骤

  1. 读取文件并进行切割
const FILE_PER_PICE_SIZE = 1024*1024*5

export const splitFile = (file) => {
  let start = 0
  let end
  let index = 0
  const { size = 0, name = '' } = file || {}
  // 最后一片需要至少为FILE_PER_PICE_SIZE大
  const totalPieces = Math.floor(size / FILE_PER_PICE_SIZE)

  const chucks = []

  while (start < size) {
    if (index === totalPieces - 1) {
      chucks.push({ chuck: file.slice(start), index: index + 1 })
      break
    }
    
    end = start + FILE_PER_PICE_SIZE
    chucks.push({ chuck: file.slice(start, end), index: index + 1 })
    start = end
    index++
  }

  return {
    total: chucks.length,
    chucks,
    name,
  }
}
  1. 文件传输前的准备,通过s3.createMultipartUpload得到此次传输的关键信息(UploadId和Key)
/* 取自官方文档 */

 var params = {
  Bucket: "examplebucket", 
  Key: "largeobject"
 };
 s3.createMultipartUpload(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
   /*
   返回data信息如下
   data = {
    Bucket: "examplebucket", 
    Key: "largeobject", 
    UploadId: "ibZBv_75gd9r8lH_gqXatLdxMVpAlj6ZQjEs.OwyF3953YdwbcQnMA2BLGn8Lx12fQNICtMw5KyteFeHw.Sjng--"
   }
   */
 });
 
  1. 使用s3.uploadPart和上一个接口返回的UploadId和Key逐一传输文件片段
/* 取自官方文档*/

 var params = {
  Body: <Binary String>,  // 文件片段放于该处
  Bucket: "examplebucket", 
  Key: "largeobject", 
  PartNumber: 1, // 范围为[1, 10000]
  UploadId: "xadcOB_7YPBOJuoFiQ9cz4P3Pe6FIZwO4f7wN93uHsNBEw97pl5eNwzExg0LAT2dUN91cOmrEQHDsP3WA60CEg--"
 };
 s3.uploadPart(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
   /*
   返回信息如下,同时需要记录该Etag和PartNumber的对应关系
   data = {
    ETag: "\"d8c2eafd90c266e19ab9dcacc479f8af\""
   }
   */
 });
 
  1. 当所有片段均成功上传后,获取文件在s3上路径
/* 取自官方文档*/

var params = {
  Bucket: "examplebucket", 
  Key: "bigobject", 
  MultipartUpload: {
   Parts: [
      {
     ETag: "\"d8c2eafd90c266e19ab9dcacc479f8af\"", 
     PartNumber: 1
    }, 
      {
     ETag: "\"d8c2eafd90c266e19ab9dcacc479f8af\"", 
     PartNumber: 2
    }
   ]
  }, 
  UploadId: "7YPBOJuoFiQ9cz4P3Pe6FIZwO4f7wN93uHsNBEw97pl5eNwzExg0LAT2dUN91cOmrEQHDsP3WA60CEg--"
 };
 s3.completeMultipartUpload(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
   /*
   data = {
    Bucket: "acexamplebucket", 
    ETag: "\"4d9031c7644d8081c2829f4ea23c55f7-2\"", 
    Key: "bigobject", 
    Location: "https://examplebucket.s3.amazonaws.com/bigobject"  // 资源的url(我们需要的部分)
   }
   */
 });
 
  1. 如果上传过程中某一个片段传输有问题,可取消本次上传
/* 取自官方文档*/

var params = {
  Bucket: "examplebucket", 
  Key: "bigobject", 
  UploadId: "xadcOB_7YPBOJuoFiQ9cz4P3Pe6FIZwO4f7wN93uHsNBEw97pl5eNwzExg0LAT2dUN91cOmrEQHDsP3WA60CEg--"
 };
 s3.abortMultipartUpload(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
 });

参考资料

docs.aws.amazon.com/AWSJavaScri…