electron實現大文件上傳


當前遇到得問題:
當electron調用系統dialog選擇文件彈窗上傳得時候,在主進程傳輸給渲染進程大得文件流數據時,頁面會出現閃退。

解決方案:

  1. 在主進程,把大的文件流分片,
  2. 再分片傳輸給渲染進程,
  3. 每個分片調用上傳文件接口,
  4. 由后台接口分片文件流,
  5. 然后由后台合並成一個完整的文件。

以下是在主進程的關鍵代碼

const _this = this
dialog.showOpenDialog({
    title: '選擇發送的文件',
    properties: ['openFile', 'multiSelections']
}).then(result => {
    if (result.filePaths && result.filePaths[0]) {
       
        // 選擇文件彈窗選擇多個大文件,每個文件都要去分片
        result.filePaths.forEach((filePath,index) => {
            // 每個分片文件流的大小
            const chunkSize = 20*1024*1024
            // fs讀取整個文件流
            const stats = fs.statSync(filePath)
            // 文件的總大小
            const size = stats.size
            // 文件分成了多少個分片
            const pieces = Math.ceil(size / chunkSize)
            const fileIndex = index
            // 此處省略代碼,把文件路徑、文件號、文件大小、分片數傳輸給渲染進程
            // 以下為關鍵代碼,注意,這里必須使用遞歸,如果使用for循環,可能會導致分片傳輸給后台的順序不對,導致合並文件出錯
            AAA(0)
            function AAA(i){
               // 每個分片結束位置
                const enddata = Math.min(size, (i+1)*chunkSize)
                //  arr存儲每個分片的文件流
                let arr = []
                 // cuSize 存儲當前分片的實際文件大小
                let cuSize = 0
                const chunkIndex = i
                // 獲取當前分片從開始到結束的文件流
                const readStream = fs.createReadStream(filePath, {
                    start: i * chunkSize,
                    end:enddata - 1
                })
                // on data讀取數據
                readStream.on('data', (data) => {
                    cuSize += data.length
                    arr.push(data)
                })
               //on end在該分片讀取完成時觸發
                readStream.on('end',()=>{
                    // 此處省略代碼,把當前分片的文件流、分片ID號、文件ID號、文件路徑、當前分片實際大小傳輸給渲染進程
                    // 用遞歸的方式去分片
                    if(i+1 < pieces){
                        AAA(i+1)
                    }
                    
                })
            }
        })
    }
})

在渲染進程的關鍵代碼

const postBigFileUpload = (params,i) => {
    const suffix = params.filePath.split('.').reverse()[0]
    // 這里服務端只接受blob對象,需要把原始的數據流轉成blob對象,這塊為了配合后端才轉
    const file = new Blob(params.fileStream[i])
    let formData = new FormData();
    formData.append('file', file); // 當前分片文件流
    formData.append('suffix', suffix); // 文件的后綴
    formData.append('chunk', i+1); // 第幾個分片,從1開始
    formData.append('chunkSize', params.chunkSize); // 當前分片大小
    formData.append('chunks', params.pieces); // 總的分片數
    formData.append('size', params.fileSize);
    axios({
        method: 'post',
        url: '/api/file/bigFileUpload',
        data: formData,
        headers: {
            'Content-Type': 'multipart/form-data',
            'X-Requested-With': 'XMLHttpRequest'
        }
    }).then(res => {
        // 上傳成功回調
    })
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM