// 获取文件名字
export const getFileName = (fileUrl=''):string => {
let u:any = '';
if(fileUrl){
if(url.parse(fileUrl)){
u = url.parse(fileUrl);
if(u.pathname){
u = u.pathname.split('/').pop();
return u;
}
}
}
return '';
};
// 打开本地文件
export const handleOpen = (path) => {
const p = path;
return judgeFileExist(path).then((res)=>{
if(res){
shell.openPath(p).catch(err=>{
shell.showItemInFolder(p);
});
return true;
}else{
return false;
}
});
};
/**
* 判断文件是否存在
* @param fileUrl 文件路径
* @returns 文件是否存在
*/
export function judgeFileExist(file: string): Promise<boolean> {
return new Promise((resolve, reject) => {
fs.access(file, fs.constants.F_OK, (err: any) => {
if (err) { // 文件存在时err = false;文件不存在时err = true
resolve(false);
} else {
resolve(true);
}
});
});
}
// 获取文件的本地路径
export const getFilePath = (url='',downloadPathCache = false) => {
let name = '';
if(downloadPathCache){
name = path.resolve(process.cwd() + '/download/Cache/' + url);
}else{
const match = url.match(/\/([\w|\.]+$)/);
name = path.resolve(process.cwd() + '/download/' + (match ? match[1] : ""));
}
return name;
};
export const setPathToLS = (path=''): void => {
if(!path) return;
const pathGroup: Array<string> = getItem(TEMP_PATH_NAME_GROUP,false) || [];
if(pathGroup.indexOf(path) === -1) {
pathGroup.push(path);
}
setItem(TEMP_PATH_NAME_GROUP, pathGroup,false);
};
export const DeletePathToLS = (path=''): void => {
if(!path) return;
let pathGroup: Array<string> = getItem(TEMP_PATH_NAME_GROUP,false) || [];
pathGroup = pathGroup.filter((item) => item !== path);
setItem(TEMP_PATH_NAME_GROUP, pathGroup,false);
};
export const checkPathInLS = (path='') => {
if(!path){
return false;
}
const pathGroup: Array<string> = getItem(TEMP_PATH_NAME_GROUP,false) || [];
if(pathGroup.length && pathGroup.indexOf(path) > -1) return true;
retu
以上是对文件操作时需要使用的方法 主要是获取文件的路径 文件名 从下载地址中解析出文件名 再将文件名存到本地存储中 取出时 需要判断文件时候存在 才决定下不下载
import { getFileName, getFilePath, setPathToLS } from './fsMethod';
const path = require('path');
const os = require('os');
const progressStream = require('progress-stream');
const fs = require('fs');
const { dialog } = require('electron');
import fetch from 'node-fetch';
const cwd = process.cwd();
const downloadStatus = [
{
status: 0,
text: '未下载'
},
{
status: 1,
text: '下载完成'
},
{
status: 2,
text: '下载失败,请重试'
},{
status: 3,
text: '文件已存在,请勿重复下载'
},{
status: 4,
text: '正在下载'
}
];
// 下载文件
export const downloadFilesByUrl = ({file_url,id},win)=> {
try {
const downloadDicPath = path.resolve(os.homedir(), cwd+ '/Download/');
if (!fs.existsSync(downloadDicPath)) {
fs.mkdirSync(downloadDicPath);
}
const file_name = getFileName(file_url);
const file_path = path.resolve(downloadDicPath, file_name);
const file_path_temp = `${file_path}.tmp`;
if (!fs.existsSync(file_path)) {
// Create write stream
const fileStream = fs.createWriteStream(file_path_temp).on('error', function (e) {
console.error('error==>', e);
}).on('ready', function () {
console.log("start download :", file_url);
}).on('finish', function () {
try {
// Rename the file after the download is complete
fs.renameSync(file_path_temp, file_path);
console.log('file download complete :', file_path);
} catch (err) {
//
}
});
// request file
fetch(file_url, {
method: 'GET',
headers: { 'Content-Type': 'application/octet-stream' },
}).then(res => {
// Get the file size data in the request header
let fsize = res.headers.get("content-length");
// Create progress
let str = progressStream({
length: fsize,
time: 100 /* ms */
});
// Download progress
str.on('progress', function (progressData) {
// output without wrapping
win.webContents.send('progressData', [{progressData:Math.round(progressData.percentage),id:id,status:downloadStatus[4]}]);
});
res.body.pipe(str).pipe(fileStream);
}).catch(e => {
// Custom exception handling
win.webContents.send('progressData', [{progressData:0,id:id,status:downloadStatus[2]}]);
console.log(e);
});
} else {
// existed
win.webContents.send('progressData', [{progressData:0,id:id,status:downloadStatus[3]}]);
console.log(path.resolve(downloadDicPath, file_name), 'already exists, do not download');
}
} catch (err) {
win.webContents.send('progressData', [{progressData:0,id:id,status:downloadStatus[2]}]);
console.log('Failed to download file, please try again later.', err);
}
};
export const mkdirsSync = (dirname)=> {
if (fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname);
return true;
}
}
};
// 保存文件
export const saveFilesByPath = (params) => {
fs.readFile(params.path,(err,data)=>{
if(err){
console.log(err);
return false;
}
dialog.showSaveDialog({
title: "保存文件",
defaultPath: params.name,
properties: ['saveFile'],
filters: [
{ name: 'All Files', extensions: ['*'] }
]
}).then(async (result) => {
let fd = fs.openSync(result.filePath, 'w');
fs.writeFileSync(fd,data);
fs.closeSync(fd);
}).catch(err => {
console.log(err);
});
});
};
// 自动下载文件
export const downloadFilesByUrlCache = (file_url)=> {
try {
const downloadDicPath = path.resolve(os.homedir(), cwd+ '/Download/Cache/');
const downloadPath = path.resolve(os.homedir(), cwd+ '/Download/');
if (!fs.existsSync(downloadPath)) {
fs.mkdirSync(downloadPath);
}
if (!fs.existsSync(downloadDicPath)) {
fs.mkdirSync(downloadDicPath);
}
const file_name = getFileName(file_url);
const file_path = path.resolve(downloadDicPath, file_name);
const file_path_temp = `${file_path}.tmp`;
if (!fs.existsSync(file_path)) {
// Create write stream
const fileStream = fs.createWriteStream(file_path_temp).on('error', function (e) {//
}).on('ready', function () {
//
}).on('finish', function () {
try {
// Rename the file after the download is complete
fs.renameSync(file_path_temp, file_path);
setPathToLS(getFilePath(file_url,true));
console.log('file download complete :', file_path);
} catch (err) {
console.log('err',err);
}
});
// request file
fetch(file_url, {
method: 'GET',
headers: { 'Content-Type': 'application/octet-stream' },
}).then(res => {
// Get the file size data in the request header
let fsize = res.headers.get("content-length");
// Create progress
let str = progressStream({
length: fsize,
time: 100 /* ms */
});
res.body.pipe(str).pipe(fileStream);
}).catch(e => {
console.log(e);
});
} else {
// existed
// console.log(path.resolve(downloadDicPath, file_name), 'already exists, do not download');
}
} catch (err) {
console.log('Failed to download file, please try again later.', err);
}
};
以上是下载逻辑
https://juejin.cn/post/7135640435011092510
这是参考链接
主要使用到了electron的
protocol模块和
session模块
// 这个需要在app.ready触发之后使用
protocol.registerFileProtocol('item', (request, callback) => {
const url = request.url.substr(7);
console.log('posturl',url,path.normalize(url),decodeURI(path.normalize(url)));
callback(decodeURI(path.normalize(url)));
});
// 这里filter参数是为了筛选过滤哪些url的请求,
session.defaultSession.webRequest.onCompleted({urls:[]}, (details) => {
// 这里可以通过details.resourceType判断请求的是否为图片类型,这里也获取了other,是因为视频也会存在在other中
if ((details.resourceType === 'image' || details.resourceType === 'other')) {
// 获取请求地址
if(!checkPathInLS(details.url)){
downloadFilesByUrlCache(details.url);
}
}
});
上面一个是增加本地文件下载协议 一个是拦截该次回话的所有请求