宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產品動態(tài)
精選推薦

大文件分片上傳的實現(xiàn)【前后臺完整版】

管理 管理 編輯 刪除


在一般的產品開發(fā)過程中,大家多少會遇到上傳視頻功能的需求,往往我們采用的都是對視頻大小進行限制等方法,來防止上傳請求超時,導致上傳失敗。這時候可能將視頻分片上傳可以對你的項目有一個小小的體驗優(yōu)化。

本片文章前端是vue,后臺基于PHP進行的分片上傳,需要的小伙伴可以借鑒。

分片上傳

1、什么是分片上傳

分片上傳,就是將所要上傳的文件,按照一定的大小,將整個文件分隔成多個數(shù)據(jù)塊(我們稱之為Part)來進行分別上傳,上傳完之后再由服務端對所有上傳的文件進行匯總整合成原始的文件。

2、分片上傳的場景

(1)大文件上傳

(2)網(wǎng)絡環(huán)境環(huán)境不好,存在需要重傳風險的場景

3、實現(xiàn)流程步驟

a、方案一,常規(guī)步驟、本文實現(xiàn)的步驟

將需要上傳的文件按照一定的分割規(guī)則,分割成相同大小的數(shù)據(jù)塊;

初始化一個分片上傳任務,返回本次分片上傳唯一標識;

按照一定的策略(串行或并行)發(fā)送各個分片數(shù)據(jù)塊;

發(fā)送完成后,服務端根據(jù)判斷數(shù)據(jù)上傳是否完整,如果完整,則進行數(shù)據(jù)塊合成得到原始文件。

b、方案二

前端(客戶端)需要根據(jù)固定大小對文件進行分片,請求后端(服務端)時要帶上分片序號和大小

服務端創(chuàng)建conf文件用來記錄分塊位置,conf文件長度為總分片數(shù),每上傳一個分塊即向conf文件中寫入一個127,那么沒上傳的位置就是默認的0,已上傳的就是Byte.MAX_VALUE 127(這步是實現(xiàn)斷點續(xù)傳和秒傳的核心步驟)

服務器按照請求數(shù)據(jù)中給的分片序號和每片分塊大?。ǚ制笮∈枪潭ㄇ乙粯拥模┧愠鲩_始位置,與讀取到的文件片段數(shù)據(jù),寫入文件。

前端代碼

template


// 上傳按鈕樣式

移入方法

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;   // 上傳時進度條展示 根據(jù)需要添加
      let st = Math.floor((chunk / allChunk) * 100);  這里是用上傳的第幾片除以總片數(shù)進行百分比計算
      this.progress = st;
    },
  });
  return false;
},
utils/upload

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) // 總片數(shù)
    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("總片數(shù)" + chunkCount)
            console.log("分片后的數(shù)據(jù)---測試:" + i)
            await uploadChunk({ chunk, currentChunk: i, chunkCount })
        }
    }
    const uploadChunk = (chunkInfo) => {
        // progressFun()
        return new Promise((resolver, reject) => {
            let config = {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }
            // 創(chuàng)建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) //總片數(shù)
            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 {
                        // 當總數(shù)大于等于分片個數(shù)的時候
                        if ((chunkInfo.currentChunk + 1) == chunkInfo.chunkCount) {
                            console.log("文件開始------合并成功")
                            success(res.data)
                        }
                    }
                }
            }).catch((e) => {
                error && error(e)
            })
        })
    }
    readFileMD5() // 開始執(zhí)行代碼
}

后端代碼

控制器

/**
     * 視頻分片上傳
     * @return mixed
     */
    public function videoUpload()
    {
        $data = $this->request->postMore([
            ['chunkNumber', 0],//第幾分片
            ['currentChunkSize', 0],//分片大小
            ['chunkSize', 0],//總大小
            ['totalChunks', 0],//分片總數(shù)
            ['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;
    }

在實現(xiàn)分片上傳的過程,需要前端和后端配合,比如前后端的上傳塊號的文件大小,前后端必須得要一致,否則上傳就會有問題。其次文件相關操作正常都是要搭建一個文件服務器的,比如使用fastdfs、hdfs等。

本示例代碼在電腦配置為4核內存8G情況下,上傳24G大小的文件,上傳時間需要30多分鐘,主要時間耗費在前端的md5值計算,后端寫入的速度還是比較快。

如果項目組覺得自建文件服務器太花費時間,且項目的需求僅僅只是上傳下載,那么推薦使用阿里的oss服務器,其介紹可以查看官網(wǎng):

https://help.aliyun.com/product/31815.html

阿里的oss它本質是一個對象存儲服務器,而非文件服務器,因此如果有涉及到大量刪除或者修改文件的需求,oss可能就不是一個好的選擇。

以上就是視頻分片上傳的前后臺的所有代碼,其中有需求小伙伴可以自行加入視頻上傳驗證,斷點續(xù)傳等操作。


請登錄后查看

徐斗明 最后編輯于2023-09-13 14:16:11

快捷回復
回復
回復
回復({{post_count}}) {{!is_user ? '我的回復' :'全部回復'}}
排序 默認正序 回復倒序 點贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復' : '回復'}}
刪除
回復
回復

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復' : '回復'}}
刪除
回復
回復
查看更多
打賞
已打賞¥{{reward_price}}
4049
{{like_count}}
{{collect_count}}
添加回復 ({{post_count}})

相關推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產品動態(tài) 精選推薦 首頁頭條 首頁動態(tài) 首頁推薦
取 消 確 定
回復
回復
問題:
問題自動獲取的帖子內容,不準確時需要手動修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內的數(shù)值
打賞成功
¥{{price}}
完成 確認打賞

微信登錄/注冊

切換手機號登錄

{{ bind_phone ? '綁定手機' : '手機登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服