當前遇到得問題:
當electron調用系統dialog選擇文件彈窗上傳得時候,在主進程傳輸給渲染進程大得文件流數據時,頁面會出現閃退。
解決方案:
- 在主進程,把大的文件流分片,
- 再分片傳輸給渲染進程,
- 每個分片調用上傳文件接口,
- 由后台接口分片文件流,
- 然后由后台合並成一個完整的文件。
以下是在主進程的關鍵代碼
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 => {
// 上傳成功回調
})
}