上传大文件切片+MD5文件加密,文件上传时对临时文件内容进行加密

此代码为写项目中遇到的,需要的可以直接复制参考使用。

 上传视频时因视频文件过大,所以需要使用分片来进行上传并MD5校验,改到前端校验后在上传,同时改为切片上传,

需要使用md5对文件的临时文件内容加密,和后端的文件相互验证文件

第一步:md5下载

npm install spark-md5

第二步:引入md5

import SparkMD5 from "spark-md5";

第三步:计算文件的MD5值 ,直接上代码

const generateMd5 = (file) => {
  console.log("fileMD5", file);
  return new Promise((resolve, reject) => {
    const chunkSize = 1024 * 1024; // 1MB 分块读取文件
    const blobSlice =
      File.prototype.slice ||
      File.prototype.mozSlice ||
      File.prototype.webkitSlice;
    const chunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0;
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();
    fileReader.onload = function (e) {
      spark.append(e.target.result); // append array buffer
      currentChunk++;
      if (currentChunk < chunks) {
        loadNext();
      } else {
        resolve(spark.end());
      }
    };
    fileReader.onerror = function (err) {
      reject(err);
    };
    function loadNext() {
      const start = currentChunk * chunkSize;
      const end =
        start + chunkSize >= file.size ? file.size : start + chunkSize;
      fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }
    loadNext();
  });
};

 用的是element-plus中的el-upload,因为我是上传视频,所以直接设置accept为:video/*,

进度条用的是:el-progress, 代码如下:

 <el-form-item label="用户视频素材" prop="saved_path">
            <el-upload
              class="upload-demo"
              drag
              accept="video/*"
              :onChange="changeUpload"
              :before-upload="handleBeforeVideoUpload"
              action="#"
              multiple
              :file-list="fileList"
            >
              <div v-if="uploadVideoTip == ''">
                <el-icon class="el-icon--upload">
                  <Plus />
                </el-icon>
                <div class="el-upload__text">点击+号上传或将文件拖拽到框内</div>
              </div>
              <div v-else><el-button>继续上传</el-button></div>

              <template #tip>
                <div
                  class="el-upload__tip"
                  style="display: flex; align-item: center"
                >
                  <span v-if="uploadVideoTip == ''"> *每个大小不得超过1G</span>
                  <span v-else>
                    <el-scrollbar height="40vh">
                      <div v-for="(item, index) in videoFiles" :key="index">
                        {{ item.name }}
                        <img
                          src="../assets/img/取消.png"
                          alt=""
                          @click="delImg(item)"
                        />
                        <el-icon
                          v-if="item.uploaded"
                          style="color: #24b023; font-size: 20px"
                          ><Check
                        /></el-icon>
                      </div>
                    </el-scrollbar>
                  </span>
                </div>
              </template>
            </el-upload>
            <el-progress :percentage="progress" v-show="progress > 0" />
          </el-form-item>

上传视频时,先通过判断文件是否大于20M,如果小于20则正常上传,如果大于20则进行分片来上传,并且MD5是加密切割之前的文件 ,代码如下:


const progress = ref(0); //视频进度

const changeUpload = async (file) => {
  console.log("视频上传file ", file);
  let { name, size, raw: uploadfile } = file;
  let chunkSize = 5 * 1024 * 1024; //默认每个分片为5M 
  // 生成的md5值························································
  let md5FileName = await generateMd5(uploadfile);

//通过判断视频文件,如果大于20M则进行分片,代码如下:

  if (size <= 20 * 1024 * 1024) {
    // 文件小于20M
    let formData = new FormData();
    formData.append("block_id", 1); //默认为1
    formData.append("block_total", 1); //默认为1
    formData.append("saved_path", uploadfile);//视频文件
    formData.append("md5_file_name", md5FileName); //MD5内容加密
    formData.append("saved_path_name", name); //文件名
    agentsUploadsApi(formData).then((res) => {
      console.log("上传res", res.data.data);
      if (res.status !== 200) {
        return;
      } else {
        if (res.data.code == 0) {
          let ids = res.data.data;
          if (ids.result.id) {
            ElMessage({
              message: "上传成功,请提交",
              type: "success",
            });
          }
        } else {
          ElMessage({
            message: res.data.msg,
            type: "error",
          });
        }
      }
    });
  } else {
    // 文件大于20M
    let chunkList = [], startSize = 0;

    while (startSize < size) {
      let endSize = Math.min(size, startSize + chunkSize);
      chunkList.push(uploadfile.slice(startSize, endSize));
      startSize += chunkSize;
    }
    for (let index = 0; index < chunkList.length; index++) {
      let chunk = chunkList[index];
      console.log("分片Blob文件", chunk);

      // 如果分片传入要的是File格式的话,就复制下面注释的这个代码,传splitFile 
      // let blob = new Blob([chunk], { type: uploadfile.type });
      // // 创建新的 File 对象来表示分片,包含文件的后缀名
      // let splitFile = new File(
      //   [blob],
      //   name.slice(0, name.lastIndexOf(".")) +
      //     index +
      //     name.slice(name.lastIndexOf(".")),
      //   { type: uploadfile.type }
      // ); 

      let formData = new FormData();
      formData.append("block_id", index + 1); //当前上传的第几块
      formData.append("block_total", chunkList.length);//总分片数
      formData.append("saved_path", chunk); //将分片传入 这是blob格式
      formData.append("md5_file_name", md5FileName);  //MD5内容加密
      formData.append("saved_path_name", name); //文件名
      //调取接口  上传为异步并使用await等待其完成
      let response = await agentsUploadsApi(formData);
      console.log("上传res", response.data.data);
      if (response.status !== 200) {
        return;
      }
      if (response.data.code == 0) {
        let ids = response.data.data;
        if (ids.result.id) {
          ElMessage({
            message: "上传成功,请提交",
            type: "success",
          });
        }
        progress.value = Math.round(((index + 1) / chunkList.length) * 100);//视频上传进度
      } else {
        ElMessage({
          message: response.data.msg,
          type: "error",
        });
      }
    }
  }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
文件切片上传是一种常见的文件上传方式,可以通过将大文件分成多个小文件,然后分别上传,最后在服务器端将这些小文件合并成一个完整的文件。这种方式可以避免上传文件网络不稳定或中断的情况,同也可以减轻服务器端的压力。 下面是一个基于 PHP 7.3 和 Vue 的大文件切片上传的示例: 前端部分: 1. 在 Vue 组件中定义一个 input 标签,用户选择需要上传文件后触发上传事件: ``` <template> <div> <input type="file" @change="uploadFile" /> </div> </template> ``` 2. 在 uploadFile 方法中,使用 FileReader API 将文件分割成多个小文件,然后使用 axios 库将这些小文件逐个上传到服务器: ``` <script> import axios from 'axios'; export default { methods: { uploadFile(event) { const file = event.target.files[0]; const chunkSize = 1024 * 1024; // 将文件分割为 1MB 的小文件 const totalChunks = Math.ceil(file.size / chunkSize); const chunks = []; for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, file.size); const chunk = file.slice(start, end); chunks.push(chunk); } const formData = new FormData(); formData.append('filename', file.name); formData.append('totalChunks', totalChunks); chunks.forEach((chunk, index) => { formData.append(`chunk${index}`, chunk); }); axios.post('/upload', formData).then(response => { console.log(response.data); }); } } }; </script> ``` 后端部分: 1. 创建一个 upload.php 文件,用于处理文件上传请求: ``` <?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $filename = $_POST['filename']; $totalChunks = $_POST['totalChunks']; $chunks = []; for ($i = 0; $i < $totalChunks; $i++) { $chunkName = "chunk{$i}"; if (isset($_FILES[$chunkName])) { $chunk = file_get_contents($_FILES[$chunkName]['tmp_name']); $chunks[] = $chunk; } } $content = implode('', $chunks); file_put_contents($filename, $content); echo 'File uploaded successfully'; } ``` 2. 在 PHP 配置文件 php.ini 中设置上传文件的最大大小和上传文件的最大数量: ``` upload_max_filesize = 100M max_file_uploads = 20 ``` 这样,就完成了一个基于 PHP 7.3 和 Vue 的大文件切片上传功能。需要注意的是,这里只是一个简单的示例,实际应用中还需要考虑上传进度、上传失败重试等问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值