当前遇到得问题:
当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 => {
// 上传成功回调
})
}