当前位置: 首页 > news >正文

视频的分片上传

分片上传需求分析:

项目中很多地方需要上传视频,如果视频很大,上传到服务器需要很多时间 ,这个时候体验就会很差。所以需要前端实现分片上传的功能。

要实现分片上传,需要对视频进行分割,分割成不同的大小进行上传,但是在上传的时候后台需要知道文件的唯一标识,进行识别,避免是重复数据上传,这个时候我们可以使用hash对内容进行生成唯一标识。

第一种方法实现:

html文件:

<input type="file" id="videoFile" accept="video/*" />

javascript 文件:

document.getElementById('uploadBtn').addEventListener('click', async () => {
    const fileInput = document.getElementById('videoFile');
    const file = fileInput.files[0];
    
    if (!file) {
        alert('请选择一个文件');
        return;
    }

    const chunkSize = 5 * 1024 * 1024; // 每个分片的大小,例如 5MB
    //分析存在几个分片,假如文件是10M ,那就是两个分片。
    const totalChunks = Math.ceil(file.size / chunkSize);
    //唯一id,这个是必须的,用来区分不同的分片
    const fileId = Date.now().toString(); // 生成一个唯一的文件ID
	
	//遍历分片,去分别上传到服务器
    for (let chunkNumber = 0; chunkNumber < totalChunks; chunkNumber++) {
        const start = chunkNumber * chunkSize;
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end);
		
		//处理数据给后端需要的格式
        const formData = new FormData();
        formData.append('file', chunk);
        formData.append('fileId', fileId);
        formData.append('chunkNumber', chunkNumber);
        formData.append('totalChunks', totalChunks);
        formData.append('fileName', file.name);

        try {
            const response = await fetch('/upload', {
                method: 'POST',
                body: formData,
            });

            if (!response.ok) {
                throw new Error('上传失败');
            }

            console.log(`分片 ${chunkNumber + 1}/${totalChunks} 上传成功`);
        } catch (error) {
            console.error('上传出错:', error);
            break;
        }
    }

    console.log('所有分片上传完成');
});

分析一下上面的formData:
在这里插入图片描述
更多的数据格式参考文章:点击跳转

服务端处理:

服务器端需要处理每个分片的上传请求,并在所有分片上传完成后将其合并。

接受分片:

服务器端可以使用类似以下的代码来接收分片:

app.post('/upload', (req, res) => {
    const { fileId, chunkNumber, totalChunks, fileName } = req.body;
    const chunk = req.files.file;

    // 保存分片到临时目录
    const chunkPath = `./temp/${fileId}-${chunkNumber}`;
    fs.writeFileSync(chunkPath, chunk.data);

    res.send({ success: true });
});

合并分片:

当所有分片上传完成后,服务器端可以将它们合并成一个完整的文件:

app.post('/merge', (req, res) => {
    const { fileId, totalChunks, fileName } = req.body;

    const outputPath = `./uploads/${fileName}`;
    const writeStream = fs.createWriteStream(outputPath);

    for (let i = 0; i < totalChunks; i++) {
        const chunkPath = `./temp/${fileId}-${i}`;
        const chunk = fs.readFileSync(chunkPath);
        writeStream.write(chunk);
        fs.unlinkSync(chunkPath); // 删除临时分片
    }

    writeStream.end();
    res.send({ success: true });
});

前端通知服务器合并分片

在所有分片上传完成后,前端可以发送一个请求通知服务器合并分片:

fetch('/merge', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        fileId: fileId,
        totalChunks: totalChunks,
        fileName: file.name,
    }),
});

第二种具体实现:

这个地方使用hash (spark-md5 第三方依赖)生成唯一标识,这个方式只对前端分片进行了封装,可以结合上面的代码传递给后端。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>视频分片上传</title>

</head>

<body>
    <input type="file" id="file"/>
    <script src="../node_modules/spark-md5/spark-md5.js"></script>

<script>
    const inp = document.querySelector('#file');
    inp.onchange = async () => {
        const file = inp.files[0];
        if(!file){
            alert("文件不存在!");
        }
       const chunks = createChunks(file,10*1024*1024);
        console.log(chunks);
        const result = await hash(chunks);
        console.log(result);
    }
	
	//生成hash
    function hash(chunks){
       return new Promise((resolve, reject) => {
           const spark = new SparkMD5();
           function _read(i){
               if(i>=chunks.length){
                   resolve(spark.end());
                   return;
               }
               const blob = chunks[i];
               const reader = new FileReader();
               reader.onload = function(e){
                   const bytes = e.target.result;//读取到的字节数组
                   spark.append(bytes);
                   _read(i+1)
               }
               reader.readAsText(blob);
           }
           _read(0);
       })
    }

    function createChunks(file,chunkSize){
        const result = [];
        for (let i = 0; i < file.size; i+=chunkSize) {
            result.push(file.slice(i,i+chunkSize));
        }
        return result;
    }
</script>

</body>
</html>

相关文章:

  • OSS(对象存储服务)
  • PostgreSQL 常用函数
  • 解锁健康密码,拥抱养生生活
  • Day9 25/2/22 SAT
  • 突破与重塑:逃离Java舒适区,借Go语言复刻Redis的自我突破和成长
  • 深度学习入门:从零开始理解神经网络
  • 顺丰java面试题_顺丰java开发面试分享,顺丰java面试经面试题
  • 代码审计初探
  • 基于CNN的FashionMNIST数据集识别3——模型验证
  • D. C05.L08.贪心算法入门(一).课堂练习4.危险的实验(NHOI2015初中)
  • 清华大学102页PPT 《deepseek从入门到精通》
  • 使用Python脚本转换YOLOv5配置文件到https://github.com/ultralytics/ultralytics:一个详细的指南
  • 《道德经的现代智慧:解码生活与商业的底层逻辑1》
  • escape SQL中用法
  • 9-1. MySQL 性能分析工具的使用——last_query_cost,慢查询日志
  • 修改/etc/hosts并生效
  • 蓝禾,oppo,游卡,汤臣倍健,康冠科技,作业帮,高途教育25届春招内推
  • jmeter 接入deepseek 或者chatgpt
  • qt.qpa.fonts: Unable to open default EUDC font: “EUDC.TTE“
  • MATLAB中isletter函数用法
  • 网站子站怎么做的/香港域名注册网站
  • 有做ppt的兼职网站吗/最新的军事新闻
  • 紫阳县城乡建设局官方网站/关键词快速排名怎么做
  • 做h网站/网站的优化与推广分析
  • 网站建设副业/优化网站的软件下载
  • html5的网站有哪些/外贸网站推广优化