Skip to content

electron 下载文件到指定目录

  1. 渲染进程点击下载按钮 把下载链接发送到主进程 ipcRenderer.invoke
  2. 主进程把文件下载临时目录中
  3. 把下载进度发送到渲染进程
  4. 渲染进程显示进度,并且显示下载成功或者失败

使用 ipcRenderer.invokeipcMain.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 来等待它完成。