首页 > 其他分享 >【前后台完整版】大文件分片上传

【前后台完整版】大文件分片上传

时间:2023-12-23 09:33:37浏览次数:41  
标签:console chunkInfo 上传 file 分片 完整版 data

在一般的产品开发过程中,大家多少会遇到上传视频功能的需求,往往我们采用的都是对视频大小进行限制等方法,来防止上传请求超时,导致上传失败。这时候可能将视频分片上传可以对你的项目有一个小小的体验优化。

本片文章前端是vue,后台基于PHP进行的分片上传,需要的小伙伴可以借鉴。

前端代码

template

<Upload
  :show-upload-list="false"
  :action="fileUrl2"
  :before-upload="videoSaveToUrl"  // 分片上传处理方法
  :data="uploadData"               // 上传时需要携带的参数 例如token之类的
  :headers="header"                // 请求头
  :multiple="true"
>
// 上传按钮样式
</Upload>

移入方法

import { uploadByPieces } from "@/utils/upload"; //引入uploadByPieces方法

methods

// 分片上传
videoSaveToUrl(file) {
  uploadByPieces({
    file: file, // 获取到的视频文件
    pieceSize: 3, // 分片大小  这里是3M一片
    success: (data) => {
      this.formValidate.video_link = data.file_path;
      this.progress = 100;    // 上传成功 进度条为100%
    },
    error: (e) => {
      this.$Message.error(e.msg);  //报错信息
    },
    uploading: (chunk, allChunk) => {
      this.videoIng = true;   // 上传时进度条展示 根据需要添加
      let st = Math.floor((chunk / allChunk) * 100);  这里是用上传的第几片除以总片数进行百分比计算
      this.progress = st;
    },
  });
  return false;
},

utils/upload

import md5 from 'js-md5' //引入MD5加密
import { upload } from '@/api/upload.js'  // 这里指前端调用接口的api方法
export const uploadByPieces = ({ file, pieceSize = 2, success, error, uploading }) => {
    // 如果文件传入为空直接 return 返回
    if (!file) return
    let fileMD5 = ''// 总文件列表
    const chunkSize = pieceSize * 1024 * 1024 // 5MB一片
    const chunkCount = Math.ceil(file.size / chunkSize) // 总片数
    console.log(chunkSize, chunkCount)
    // 获取md5
    const readFileMD5 = () => {
        // 读取视频文件的md5
        console.log("获取文件的MD5值")
        let fileRederInstance = new FileReader()
        console.log('file', file)
        fileRederInstance.readAsBinaryString(file)
        fileRederInstance.addEventListener('load', e => {
            let fileBolb = e.target.result
            fileMD5 = md5(fileBolb)
            console.log('fileMD5', fileMD5)
            console.log("文件未被上传,将分片上传")
            readChunkMD5()
        })
    }
    const getChunkInfo = (file, currentChunk, chunkSize) => {
        let start = currentChunk * chunkSize
        let end = Math.min(file.size, start + chunkSize)
        let chunk = file.slice(start, end)
        return { start, end, chunk }
    }
    // 针对每个文件进行chunk处理
    const readChunkMD5 = async () => {
        // 针对单个文件进行chunk上传
        for (var i = 0; i < chunkCount; i++) {
            const { chunk } = getChunkInfo(file, i, chunkSize)
            console.log("总片数" + chunkCount)
            console.log("分片后的数据---测试:" + i)
            await uploadChunk({ chunk, currentChunk: i, chunkCount })
        }
    }
    const uploadChunk = (chunkInfo) => {
        // progressFun()
        return new Promise((resolver, reject) => {
            let config = {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }
            // 创建formData对象,下面是结合不同项目给后端传入的对象。
            let fetchForm = new FormData()
            fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)  // 第几片
            fetchForm.append('chunkSize', chunkSize)  // 分片大小的限制  例如限制 5M
            fetchForm.append('currentChunkSize', chunkInfo.chunk.size)  // 每一片的大小
            fetchForm.append('file', chunkInfo.chunk)   //每一片的文件
            fetchForm.append('filename', file.name)  // 文件名 
            fetchForm.append('totalChunks', chunkInfo.chunkCount) //总片数
            fetchForm.append('md5', fileMD5)
            upload(fetchForm, config).then(res => {
                console.log("分片上传返回信息:", res)
                if (res.data.code == 1) {
                    // // 结合不同项目 将成功的信息返回出去
                    // 下面如果在项目中没有用到可以不用打开注释
                    uploading(chunkInfo.currentChunk + 1, chunkInfo.chunkCount)
                    resolver(true)
                } else if (res.data.code == 2) {
                    if (chunkInfo.currentChunk < chunkInfo.chunkCount - 1) {
                        console.log("分片上传成功")
                    } else {
                        // 当总数大于等于分片个数的时候
                        if ((chunkInfo.currentChunk + 1) == chunkInfo.chunkCount) {
                            console.log("文件开始------合并成功")
                            success(res.data)
                        }
                    }
                }
            }).catch((e) => {
                error && error(e)
            })
        })
    }
    readFileMD5() // 开始执行代码
}

后端代码

控制器

/**
     * 视频分片上传
     * @return mixed
     */
    public function videoUpload()
    {
        $data = $this->request->postMore([
            ['chunkNumber', 0],//第几分片
            ['currentChunkSize', 0],//分片大小
            ['chunkSize', 0],//总大小
            ['totalChunks', 0],//分片总数
            ['file', 'file'],//文件
            ['md5', ''],//MD5
            ['filename', ''],//文件名称
        ]);
        $res = $this->service->videoUpload($data, $_FILES['file']);
        return app('json')->success($res);
    }

方法

/**
     * 视频分片上传
     * @param $data
     * @param $file
     * @return mixed
     */
    public function videoUpload($data, $file)
    {
        $public_dir = app()->getRootPath() . 'public';
        $dir = '/uploads/attach/' . date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d');
        $all_dir = $public_dir . $dir;
        if (!is_dir($all_dir)) mkdir($all_dir, 0777, true);
        $filename = $all_dir . '/' . $data['filename'] . '__' . $data['chunkNumber'];
        move_uploaded_file($file['tmp_name'], $filename);
        $res['code'] = 0;
        $res['msg'] = 'error';
        $res['file_path'] = '';
        if ($data['chunkNumber'] == $data['totalChunks']) {
            $blob = '';
            for ($i = 1; $i <= $data['totalChunks']; $i++) {
                $blob .= file_get_contents($all_dir . '/' . $data['filename'] . '__' . $i);
            }
            file_put_contents($all_dir . '/' . $data['filename'], $blob);
            for ($i = 1; $i <= $data['totalChunks']; $i++) {
                @unlink($all_dir . '/' . $data['filename'] . '__' . $i);
            }
            if (file_exists($all_dir . '/' . $data['filename'])) {
                $res['code'] = 2;
                $res['msg'] = 'success';
                $res['file_path'] = $dir . '/' . $data['filename'];
            }
        } else {
            if (file_exists($all_dir . '/' . $data['filename'] . '__' . $data['chunkNumber'])) {
                $res['code'] = 1;
                $res['msg'] = 'waiting';
                $res['file_path'] = '';
            }
        }
        return $res;
    }

 

以上就是视频分片上传的前后台的所有代码,其中有需求小伙伴可以自行加入视频上传验证,断点续传等操作。

 

参考文章:http://blog.ncmem.com/wordpress/2023/12/23/%e3%80%90%e5%89%8d%e5%90%8e%e5%8f%b0%e5%ae%8c%e6%95%b4%e7%89%88%e3%80%91%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%86%e7%89%87%e4%b8%8a%e4%bc%a0/

欢迎入群一起讨论

 

 

标签:console,chunkInfo,上传,file,分片,完整版,data
From: https://www.cnblogs.com/songsu/p/17922707.html

相关文章

  • 大文件、视频分片上传,断点续传
    需求背景再简单的需求,遇到巨大的任务量,也会变得很棘手在项目中,难免会需要一些大的文件、视频上传,通常都会耗费很长的时间上传到服务器然鹅,这其中不能出现任何的差错(网页刷新,关机、断网)之类的故障,一旦发生了,之前的努力都会付之东流,重新开始上传之路,这时候就体现出分片上传、断点续......
  • sonarqube搭建超级完整版
    sonarqube搭建超级完整版sonarqube搭建超级完整版参考文章https://www.jianshu.com/p/b35674bd2fadSonar(SonarQube)是一个开源平台,用于管理源代码的质量。Sonar不只是一个质量数据报告工具,更是代码质量管理平台。支持java,JavaScrip,Scala等等二十几种编程语言的代......
  • vue实现大文件分片上传与断点续传到七牛云
    问题:前段时间做视频上传业务,通过网页上传视频到服务器。视频大小小则几十M,大则1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1、文件过大,超出服务端的请求大小限制;2、请求时间过长,请求超时;3、传输中断,必须重新上传导致前功尽弃;探索过程:1、原先咨询过组里的大佬给......
  • input 上传图片文件限制文件大小和宽高
    用h5 inputtype="file"上传图片文件html设置  拼接到需要的地方varcheckboxHtml='<formenctype="multipart/form-data">n'+<divclass="modal-body">n'+<divclass="my-img">+</div>n'+<......
  • Vue + Django 使用wangeditor 上传图片 显示跨域报错
    报错:newsDetailed:1 AccesstoXMLHttpRequestat'http://www.py32api.com:8000/users/uploadFile/'fromorigin'http://localhost:8080'hasbeenblockedbyCORSpolicy:RequestheaderfieldtokenisnotallowedbyAccess-Control-Allow-Head......
  • C# 通过SshNet上传下载文件
    会把本地文件夹压缩成 .tar.gz文件后上传usingICSharpCode.SharpZipLib.GZip;usingICSharpCode.SharpZipLib.Tar;usingRenci.SshNet;usingSystem;usingSystem.IO;usingSystem.Windows.Forms;namespacePack{publicdelegatevoidAddTextLog(stringlog);......
  • asp.net core 3.x 解决文件上传大小限制
    如在Kestrel服务器下可以选择在CreateHostBuilder方法中统一移除所有上传限制。也可在指定的action上添加[DisableRequestSizeLimit]属性解除限制。//第一种在CreateHostBuilder中添加配置。publicstaticIHostBuilderCreateHostBuilder(string[]args){......
  • vue+element 上传文件及文件夹
    有需求需要做一个上传压缩包及文件夹的需求,记性不好,记录一下。HTML使用的element的upload和form表单,dropdown下拉菜单<div><el-col:span="24"><el-form-itemlabel="材料路径:"prop="fileName"><el-col:span="21&qu......
  • django+vue实现文件夹上传
    最近学django的文件上下传,网上的文件夹上下传压根没有,找了好几个,报错一大堆,没有一个能用,花里胡哨,可气!!!下面这个方法是我刚刚用过的,分享给大家。前端vue非常简单,template部分<inputtype="file"id="twos"webkitdirectory/><el-buttontype="primary"@click="sumfolder">文件夹......
  • Python接口自动化之文件上传/下载接口详解
    〇、前言文件上传/下载接口与普通接口类似,但是有细微的区别。如果需要发送文件到服务器,例如:上传文档、图片、视频等,就需要发送二进制数据,上传文件一般使用的都是Content-Type:multipart/form-data数据类型,可以发送文件,也可以发送相关的消息体数据。反之,文件下载就是将二进制格式......