学习笔记01-前端分片上传

62 阅读2分钟

写这篇文章就是为了养成良好习惯,将最近的一些学习记录下来,防止忘记,好记性不如烂笔头。

这里我使用的files.slice 方法来完成分片,使用npm i crc库计算crc32值。

let files = file
  //切片大小 10kb
  const chunkSize = 1024 * 1024 * 2;
  let currentChunk = 0;
  let indexChunk = 1;
  //切片数组
  const chunkList = [];
  // 创建一个FileReader对象,用于读取文件
  const fileR = new FileReader();
  // 读取文件作为ArrayBuffer
  fileR.readAsArrayBuffer(files);
  fileR.onload = function(e) {
    let file = e.target.result;
    // 当文件读取完成后,计算原始文件文件的crc32校验值
    files.crc32 = crc32(file).toString(16);
    console.log(files.crc32);
  };
  while (currentChunk < files.size) {
    let chunk = files.slice(currentChunk, currentChunk + chunkSize);
    // 将片段转换为ArrayBuffer,然后计算片段的crc32校验值
    await chunk.arrayBuffer().then(res => {
    //切边数组组装(切片大小,原始大小,切片crc32值,切片文件名)
      let formData = {
        file: chunk,
        size: chunk.size,
        fileName: files.name,
        chunkName: `${files.name}_${indexChunk}`,
        crc32: crc32(res).toString(16)
      };
      chunkList.push(formData);
    });
    currentChunk += chunkSize;
    indexChunk += 1;
  }

这里我使用 express 完成了一个简单的后端保存切片合并切片,以及检查文件是否上传过。前端切片总体来说是一个比较简单的小功能,这里我没有对流程做任何优化,后端也没有对文件进行校验。所以简单的小功能做好也要花一番心思。我想说的就这么多了。

//合并
app.post("/merge", multi,(req, res) => {
  try {
    const { oldCrc32 ,fileName } = req.body;
    console.log("merge");
    //打开临时文件夹
    let Directory = path.join(__dirname, "/upload/", oldCrc32);
    //合并后文件存放位置
    let filePath = path.join(__dirname, "/upload/", fileName);
    //读取文件列表
    fs.readdir(Directory, (err, fileList) => {
      if(!err){
        let pool = fileList.map(item=>new Promise(resolve=>{
          let chunkPath = path.join(Directory, item);
          //将切片文件写入新文件中-合并文件
          fs.appendFileSync(filePath,fs.readFileSync(chunkPath));
          resolve()
        }));
        Promise.all(pool).then(()=>{
          fs.rmdirSync(Directory);
          res.send({
            code: 200,
            msg: "成功",
          });
        })
      }
    });
  }catch{
    console.log("失败")
  }
});
// 上传
app.post("/upload", multi, (req, res) => {
  const { file, ...data } = req.body;
  console.log("upload", req.files);
  try {
    // 使用总文件crc32值作为临时文件夹名称
    let Directory = path.join(__dirname, "/upload/", data.oldCrc32);
    fs.stat(Directory, (err, stats) => {
      // 判断该文件是否有过上传
      if (!stats) {
        //没有则直接创建文件夹并上传
        fs.mkdir(Directory, (err) => {
          if (err) {
            console.log("失败" + err);
          } else {
            let fileName = path.join(Directory, data.chunkName);
            const files = fs.readFileSync(req.files.file.path);
            fs.writeFile(fileName, files, (err) => {
              if (err) {
                console.log("失败" + err);
              } else {
                res.send({
                  code: 200,
                  msg: "成功",
                });
              }
            });
          }
        });
      } else {
        //有则查询该切片是否被上传过
        let fileName = path.join(Directory, data.chunkName);
        fs.stat(fileName, (err, stats) => {
          if (!stats) {
            //该切片未被上传过
            const files = fs.readFileSync(req.files.file.path);
            fs.writeFile(fileName, files, (err) => {
              if (err) {
                console.log("失败" + err);
              } else {
                res.send({
                  code: 200,
                  msg: "成功",
                });
              }
            });
          } else {
            //该切片已经被上传过
            res.send({
              code: 200,
              msg: "文件存在",
            });
            // let crc = crc32(file.file);
          }
        });
      }
    });
  } catch (err) {
    console.log("失败" + err);
  }
});
//检查
app.post("/verify", multi, (req, res) => {
  try {
    const { file, ...data } = req.body;
    console.log("verify", req.files);
    let Directory = path.join(__dirname, "/upload/", data.oldCrc32);
    fs.stat(Directory, (err, stats) => {
      // 检查文件夹是否存在
      if (!stats) {
        res.send({
          code: 200,
          msg: "成功",
        });
      } else {
        let fileName = path.join(Directory, data.chunkName);
        fs.stat(fileName, (err, stats) => {
          //检查文件是否上传过
          if (!stats) {
            res.send({
              code: 200,
              msg: "失败",
            });
          } else {
            //文件已经上传过
            res.send({
              code: 200,
              msg: "文件存在",
            });
          }
        });
      }
    });
  } catch {}
});