如何将大文件直接下载到磁盘,而不将其存储在服务器和浏览器的 RAM 中?

How to download a big file directly to the disk, without storing it in RAM of a server and browser?

我想使用 Node.js 和 [= 从运行我的应用程序的同一台服务器(没有外部云文件存储,也就是本地)实现大文件下载(大约 10-1024 Mb) 63=].

我想出了如何将整个文件转换为 Blob,通过网络传输它,然后生成下载 link 和 window.URL.createObjectURL(…)Blob。只要文件很小,这种方法就非常有效,否则不可能将整个 Blob 保存在服务器和客户端的 RAM 中。

我尝试使用 File APIAJAX 实现其他几种方法,但它看起来 Chrome 将整个文件加载到 RAM 中,然后才将其转储到磁盘。同样,小文件可能没问题,但大文件就不行了。

我最后一次尝试发送一个基本的 Get-请求:

const aTag = document.createElement("a");
aTag.href = `/downloadDocument?fileUUID=${fileName}`;
aTag.download = fileName;
aTag.click();

在服务器端:

app.mjs

app.get("/downloadDocument", async (req, res) => {

    req.headers.range = "bytes=0";

    const [urlPrefix, fileUUID] = req.url.split("/downloadDocument?fileUUID=");

    const downloadResult = await StorageDriver.fileDownload(fileUUID, req, res);

});

StorageDriver.mjs

export const fileDownload = async function fileDownload(fileUUID, req, res) {

    //e.g. C:\Users\User\Projects\POC\assets\wanted_file.pdf
    const assetsPath = _resolveAbsoluteAssetsPath(fileUUID);

    const options = {
        dotfiles: "deny",
        headers: {
            "Content-Disposition": "form-data; name=\"files\"",
            "Content-Type": "application/pdf",
            "x-sent": true,
            "x-timestamp": Date.now()
        }
    };

    res.sendFile(assetsPath, options, (err) => {

        if (err) {
            console.log(err);
        } else {
            console.log("Sent");
        }

    });

};

当我单击 link 时,Chrome 会在“下载”中显示该文件,但状态为 失败 - 无文件。下载目标中没有文件。

我的问题:

  1. 为什么在发送 Get 请求时我得到 失败 - 没有文件
  2. 据我了解,res.sendFile对于小文件来说是一个正确的选择,但是对于大文件来说,最好使用res.write,它可以被分割成块。是否可以将 res.writeGet-请求一起使用?

P.S。我已经详细阐述了这个问题,以使其更加狭窄和清晰。之前这个问题的重点是从 Dropbox 下载一个大文件而不将其存储在 RAM 中,可以找到答案:

Chrome无法显示下载进度,因为文件正在后台下载。下载后,将创建文件的 link 并“单击”以强制 Chrome 显示已下载文件的对话框。

可以更轻松地完成。您需要创建一个 GET 请求并让浏览器下载文件,而无需 ajax.

app.get("/download", async (req, res, next) => {
  const { fileName } = req.query;
  const downloadResult = await StorageDriver.fileDownload(fileName);
  res.set('Content-Type', 'application/pdf');
  res.send(downloadResult.fileBinary);
});
function fileDownload(fileName) {
  const a = document.createElement("a");
  a.href = `/download?fileName=${fileName}`;
  a.download = fileName;
  a.click();
}