electron 下载文件到指定目录
- 渲染进程点击下载按钮 把下载链接发送到主进程 ipcRenderer.invoke
- 主进程把文件下载临时目录中
- 把下载进度发送到渲染进程
- 渲染进程显示进度,并且显示下载成功或者失败
使用 ipcRenderer.invoke
和 ipcMain.handle
是一个更好的方式,它允许在主进程完成操作后返回结果给渲染进程。
以下是相应的示例代码:
渲染进程:
javascript
const { ipcRenderer } = require("electron");
// 假设你有一个按钮用于触发下载
const downloadButton = document.getElementById("downloadButton");
const progressBar = document.getElementById("progressBar"); // 假设你有一个进度条元素
downloadButton.addEventListener("click", () => {
const fileUrl = "https://example.com/path/to/file"; // 你想下载的文件 URL
const outputFileName = "file.ext"; // 你想保存的文件名
ipcRenderer
.invoke("download", { fileUrl, outputFileName })
.then((outputPath) => {
console.log("文件已成功下载到临时目录:", outputPath);
// 这里可以处理下载完成后的逻辑
});
ipcRenderer.on("download progress", (event, progress) => {
console.log(`Download progress: ${progress}%`);
progressBar.value = progress; // 更新进度条
});
});
主进程:
javascript
const fs = require("fs");
const axios = require("axios");
const os = require("os");
const path = require("path");
const { ipcMain } = require("electron");
ipcMain.handle("download", (event, { fileUrl, outputFileName }) => {
const outputLocationPath = path.join(os.tmpdir(), outputFileName);
const writer = fs.createWriteStream(outputLocationPath);
let receivedBytes = 0;
return axios({
method: "get",
url: fileUrl,
responseType: "stream"
}).then((response) => {
const totalBytes = response.headers["content-length"];
response.data.on("data", (chunk) => {
receivedBytes += chunk.length;
let progress = Math.floor((receivedBytes / totalBytes) * 100);
// 发送进度给渲染进程
event.sender.send("download progress", progress);
});
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on("finish", () => {
resolve(outputLocationPath);
});
writer.on("error", reject);
});
});
});
这个示例完成了你所描述的步骤:在渲染进程中触发下载,然后在主进程中下载文件并返回下载进度给渲染进程,最后在渲染进程中更新下载进度并处理下载完成后的逻辑。
5. 下载完成在主进程调用 shell.openPath 默认程序打开文件
好的,如果你需要在下载完成后自动使用默认程序打开文件,你可以使用 electron
中的 shell.openPath()
方法。这个方法会打开给定的文件或目录在系统默认的应用中。
以下是如何添加到主进程的代码:
javascript
const fs = require("fs");
const axios = require("axios");
const os = require("os");
const path = require("path");
const { ipcMain, shell } = require("electron");
ipcMain.handle("download", (event, { fileUrl, outputFileName }) => {
const outputLocationPath = path.join(os.tmpdir(), outputFileName);
const writer = fs.createWriteStream(outputLocationPath);
let receivedBytes = 0;
return axios({
method: "get",
url: fileUrl,
responseType: "stream"
}).then((response) => {
const totalBytes = response.headers["content-length"];
response.data.on("data", (chunk) => {
receivedBytes += chunk.length;
let progress = Math.floor((receivedBytes / totalBytes) * 100);
// 发送进度给渲染进程
event.sender.send("download progress", progress);
});
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on("finish", async () => {
// 使用默认程序打开文件
await shell.openPath(outputLocationPath);
resolve(outputLocationPath);
});
writer.on("error", reject);
});
});
});
在这个例子中,shell.openPath(outputLocationPath)
将会在下载完成后调用,打开下载的文件。这个函数是异步的,所以我使用了 await
来等待它完成。