类似于给一个path路径 将路径读取切片上传 请问一下 fs读取 怎么将读取的信息转为new file呢,不是很清楚 ,
/**
* 文件上传模块
* created by fish 2020-02-02
*/
import fileBus from '@/assets/config/fileBus';
import axios from 'axios';
import Vue from 'vue';
import config from '@/assets/config/config';
import store from '@/store';
import {Message} from 'iview';
import {api_file} from '@/assets/api/api';
const fs = require('original-fs');
let Uplaoder = (()=>{
const chunkSize = 2097152; //分片大小
const retry = 3; //重置次数
const limitUploadNum = 3;//同时上传数量
const App = require('electron').remote.app;
let waitUploadList = [];//等待上传中的队列
let isUploadingList = [];//正在上传的队列
let uploadCancel = [];
let mergeTimer = [];
/**
* 初始化
* @param {*} option
*/
let init = (option,callback)=>{
// 将每个上传的文件拉进等待队列
waitUploadList.push(option.fileInfo);
}
let resetList = (pid)=>{
if(pid){
for(let i=0;i<isUploadingList.length;i++){
if(pid==isUploadingList[i].pid){
isUploadingList.splice(i,1);
break;
}
}
}
let dbinfoArr = waitUploadList.splice(0,limitUploadNum-isUploadingList.length);
dbinfoArr.forEach(ele=>{
let isExis = false;
for(let i=0;i<isUploadingList.length;i++){
if(isUploadingList[i].pid == ele.pid){
isExis = true;
break;
}
}
if(!isExis){
isUploadingList.push(ele);
startUpload(ele);
}
});
}
let startUpload = (fileInfo)=>{
//文件上传队列
uploadCancel[fileInfo.pid] = axios.CancelToken.source();
chunkfile(fileInfo);
}
/**
* 生成文件基本数据
* @param {*} option
*/
let createFileInfo = (option)=>{
return new Promise((resolve)=>{
resolve(
{
pid: App.loginData.user_id+''+Date.now(),//唯一pid
file: option.file, //file数据
percent: 0, //进度
name: option.file.name,
uploadpath: option.path, //上传路径1
size: option.file.size,
user_id: App.loginData.user_id,
retry: 3, //重置次数
isCloud: store.state.isCloudFile,//内网还是外网
//类型 1是下载 2上传
file_type: 2,
r_bite: 0,
t_bite: option.file.size,
//4:未开始 1 上传成功 2 上传中 3 取消 -1 失败 6合并中 5文件名称非法 7文件删除或者改名
file_status: 4,
speed:0,
startSize:0,
chunk: 1, //当前 分片num
chunks: Math.ceil(option.file.size / chunkSize),//分片总数
file_path: option.file.path
}
)
});
}
let chunkfile = (option)=>{
uploadfile(option, 1, []);
}
/**
* 分片文件流
* @param {*} option
* @param {*} endBite
*/
let getFileStream = (option,endBite)=>{
return new Promise((resolve,reject)=>{
let start_bite = option.r_bite;
let end_bite = start_bite+2*chunkSize;//截取流文件 初始流+4MB大小
let bufferArr = [];
let fileStream = fs.createReadStream(option.file_path,{
autoClose: true,
start: option.r_bite,
end: end_bite
});
fileStream.on('data',function(chunk){
bufferArr.push(chunk);
});
fileStream.on('end',function(){
let slice_end_bite = chunkSize;
if(option.chunk==option.chunks){
slice_end_bite = option.size-(option.chunk-1)*chunkSize;
}
var reader = Buffer.concat(bufferArr);
let result = reader.slice(0,slice_end_bite);
let myfile = new File([result],option.name,{type:option.file.type});
option.receive_stream = myfile;
option.endBite = option.r_bite+myfile.size;
resolve(option);
})
fileStream.on('error',function(error){
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: option.r_bite,
t_bite: option.size,
status: 7,
chunk: option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
return;
});
});
}
let uploadfile = (_option)=>{
let endBite = 0;
if(_option.chunk<_option.chunks){
endBite = _option.chunk*chunkSize;
}else{
endBite = _option.size;
}
let upedSize = 0;
if(_option.chunk<=_option.chunks){
getFileStream(_option,endBite).then((option)=>{
option.startSize = 0;
option.startTime = new Date().getTime();
let formatData = new FormData();
formatData.append('file',option.receive_stream);
formatData.append('path',option.uploadpath);
formatData.append('fname',option.name);
formatData.append('file_md5', option.pid);
formatData.append('chunk', option.chunk-1);
formatData.append('chunks',option.chunks);
let url= option.isCloud?'/file/file/v1/upload':'/file/v1/upload';
let instance = axios.create({
baseURL: option.isCloud?config.baseUrl:config.localBaseUrl,
timeout: 30000
});
instance({
url: url,
method:'post',
data: formatData,
headers:{
Authorization: "bearer " + (option.isCloud?App.loginData.token.token:App.loginData.internal_token),
"Content-Type":"multipart/form-data"
},
cancelToken: uploadCancel[option.pid].token,
onUploadProgress:(e)=>{
let currentTime = new Date().getTime();
var timeUsed = currentTime-option.startTime;
upedSize= option.r_bite+e.loaded;
let speed = (e.loaded / timeUsed * 1000).toFixed(0) || 0;
let percent = parseInt((parseInt(option.r_bite) / parseInt(option.size) * 100));
fileBus.$emit('fileUploadProcess',{
pid: option.pid,
percent: percent,
name: option.name,
speed: speed,
r_bite: upedSize,
t_bite: option.size,
status: 2,
chunk: option.chunk-1,
chunks: option.chunks,
});
}
}).then(res=>{
if(res.status==200){
if(res.data.code=='40004'){
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: 0,
t_bite: option.size,
status: 5,
chunk: 0,
chunks: option.chunks,
});
resetList(option.pid);
return;
}
if(res.data.code=='40005'){
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: 0,
t_bite: option.size,
status: -1,
chunk: 0,
chunks: option.chunks,
});
resetList(option.pid);
return;
}
if(res.data.code ==0){
option.r_bite = option.endBite;
option.startSize = upedSize;
if(res.data.data.key){
//小文件
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: 1,
chunk: option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
return;
}
//分片
if(res.data.data.is_merge){
mergeFile(option);
resetList(option.pid);
return;
}
if(option.chunk == option.chunks){
mergeFile(option);
}
++option.chunk;
uploadfile(option);
}else{
--option.retry;
if(option.retry>0){
uploadfile(option);
}else{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: option.r_bite,
t_bite: option.size,
status: -1,
chunk: option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
}
}
}else{
--option.retry;
if(option.retry>0){
uploadfile(option);
}else{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: option.r_bite,
t_bite: option.size,
status: -1,
chunk:option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
}
}
}).catch(err=>{
if(err.message == 'pause'){
let percent = parseInt((parseInt(option.r_bite) / parseInt(option.size) * 100));
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: percent,
name: option.name,
speed: 0,
r_bite: option.r_bite,
t_bite: option.size,
status: 3,
chunk: option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
return;
}
--option.retry;
if(option.retry>0){
uploadfile(option);
}else{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: option.r_bite,
t_bite: option.size,
status: -1,
chunk: option.chunk-1,
chunks: option.chunks,
});
resetList(option.pid);
}
});
});
}
}
/**
* 合并文件
* @param {*} option
* @param {*} file
* @param {*} chunk
* @param {*} chunks
*/
let mergeFile = (option)=>{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: 6,
chunk: option.chunk,
chunks: option.chunks,
});
let url = (option.isCloud?config.baseUrl:config.localBaseUrl)+(option.isCloud?'/file':'')+'/file/v1/mergefile';
axios({
url:url,
method:'post',
headers:{
"Authorization":'bearer '+(option.isCloud?App.loginData.token.token:App.loginData.internal_token)
},
data:{
fname: option.name,
path: option.uploadpath,
file_md5: option.pid,
hide_loading: true
}
}).then(res=>{
if(res.code==0){
checkFileMergeState(res.data.hash,option);
}else{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 0,
name: option.name,
speed: 0,
r_bite: 0,
t_bite: option.size,
status: -1,
chunk: 0,
chunks: 0,
});
resetList(option.pid);
}
}).catch(err=>{
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: -1,
chunk:option.chunk,
chunks: option.chunks,
});
resetList(option.pid);
});
}
/**
* 检测文件合并状态
* @param {*} data
* @param {*} deleteData
*/
let checkFileMergeState = (hash,option)=>{
return new Promise((resolve,reject)=>{
if(mergeTimer[option.pid] != null){
clearTimeout(mergeTimer[option.pid]);
mergeTimer[option.pid] =null;
delete mergeTimer[option.pid];
}
let numCount=0;
mergeTimer[option.pid] = setInterval(() => {
api_file.checkFileMergeState({
hide_loading: true,
hash: hash,
isCloud: option.isCloud
}).then(res=>{
if(res.code==0){
if(res.data.status==1){
clearInterval(mergeTimer[option.pid]);
mergeTimer[option.pid] = null;
delete mergeTimer[option.pid]
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: 1,
chunk: option.chunk,
chunks: option.chunks,
});
resetList(option.pid);
}else if(res.data.status == 0){
numCount++;
if(numCount<100){
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: 6,
chunk: option.chunk,
chunks: option.chunks,
});
}else{
clearInterval(mergeTimer[option.pid]);
mergeTimer[option.pid] = null;
delete mergeTimer[option.pid]
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: -1,
chunk: option.chunk,
chunks: option.chunks,
});
resetList(option.pid);
}
}else{
clearInterval(mergeTimer[option.pid]);
mergeTimer[option.pid] = null;
delete mergeTimer[option.pid];
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: -1,
chunk: option.chunk,
chunks: option.chunks,
});
resetList(option.pid);
}
}else{
clearInterval(mergeTimer[option.pid]);
mergeTimer[option.pid] = null;
delete mergeTimer[option.pid];
fileBus.$emit('fileUploadSuccess',{
pid: option.pid,
percent: 100,
name: option.name,
speed: 0,
r_bite: option.size,
t_bite: option.size,
status: -1,
chunk: option.chunk,
chunks: option.chunks,
});
resetList(option.pid);
}
});
}, 3000);
});
}
/**
* 中止及删除文件
* @param {*} data
* @param {*} deleteData
*/
let abortFileUpload = (data,deleteData)=>{
for(let i=0;i<waitUploadList.length;i++){
//如果删除的文件处于等待队列中 就需要把队列中的也删掉
if(waitUploadList[i].pid == data.pid){
waitUploadList.splice(i,1);
break;
}
}
//合并中止
if(mergeTimer[data.pid]){
clearInterval(mergeTimer[data.pid]);
delete mergeTimer[data.pid];
}
//上传中止
if(uploadCancel[data.pid]){
uploadCancel[data.pid].cancel('pause');
}
if(deleteData){
let keys = 'ecis'+App.loginData.user_id+'.'+data.pid
Vue.fileStore.delete(keys)
deleteData();
}else{
fileBus.$emit('fileUploadSuccess',{
pid: data.pid,
percent: data.percent,
name: data.name,
speed: 0,
r_bite: data.r_bite,
t_bite: data.t_bite,
status: 3,
chunk: data.chunk,
chunks: data.chunks,
});
}
resetList(data.pid);
}
/**
* 重新上传
* @param {*} data
*/
let reFileUpload = (_fileInfo)=>{
let fileInfo = JSON.parse(JSON.stringify(_fileInfo));
if(fs.existsSync(fileInfo.file.path)){
fileInfo.retry = retry;
++fileInfo.chunk;
uploadCancel[fileInfo.pid] = axios.CancelToken.source();
uploadfile(fileInfo);
}else{
Message.info('本地文件已删除,请重新上传');
fileBus.$emit('removeFile',fileInfo);
}
}
/**
* 中止全部
*/
let abortAll = ()=>{
for(let key in uploadCancel){
uploadCancel[key].cancel('pause');
}
}
return {
init,
abortFileUpload,
reFileUpload,
abortAll,
resetList,
createFileInfo
}
})();
export default Uplaoder;
createReadStream
10 回答11.1k 阅读
6 回答3k 阅读
5 回答4.8k 阅读✓ 已解决
4 回答3k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
3 回答5.1k 阅读✓ 已解决
3 回答1.8k 阅读✓ 已解决
你的意思是要选取文件夹 然后多上传嘛? 如果是这个 目前来说 兼容性并不好 有两种方式
一种是 <input type='file' webkitdirectory> webkitdirectory 是一个非标准的属性
一种是 showDirectoryPicker() showDirectoryPicker 是一个全新的API