从 Blob 保存到本地文件

IT技术 javascript download blob client-side
2021-03-12 02:33:40

我有一个棘手的问题要问你,我已经为此苦苦挣扎了一段时间。

我正在寻找一种解决方案,我可以在其中将文件保存到用户计算机,而无需本地存储,因为本地存储有 5MB 的限制。我想要“保存到文件”对话框,但我想要保存的数据仅在 javascript 中可用,我想防止将数据发送回服务器,然后再次发送。

用例是,我正在处理的服务正在保存用户数据的压缩和加密块,因此服务器不知道这些块中的内容,并且通过将数据发送回服务器,这将导致 4 倍的流量和服务器正在接收未加密的数据,这将使整个加密无用。

我找到了一个 javascript 函数,可以使用“保存到文件”对话框将数据保存到用户计算机,但是这方面的工作已经停止并且没有得到完全支持。是这样的:http : //www.w3.org/TR/file-writer-api/

因此,由于我没有 window.saveAs,有什么方法可以在不将所有内容发送到服务器的情况下从 Blob 对象保存数据?

如果我能得到提示,搜索什么,那就太好了。

我知道这行得通,因为 MEGA 正在这样做,但我想要我自己的解决方案 :)

5个回答

您最好的选择是使用 blob url(这是一个指向浏览器内存中对象的特殊 url):

var myBlob = ...;
var blobUrl = URL.createObjectURL(myBlob);

现在您可以选择简单地重定向到这个 url ( window.location.replace(blobUrl)),或者创建一个指向它的链接。第二种解决方案允许您指定默认文件名:

var link = document.createElement("a"); // Or maybe get it from the current document
link.href = blobUrl;
link.download = "aDefaultFileName.txt";
link.innerHTML = "Click here to download the file";
document.body.appendChild(link); // Or append it whereever you want

FileSaver.jssaveAs为某些没有它的浏览器实现

https://github.com/eligrey/FileSaver.js

使用 FileSaver.js 1.3.8 测试,在 Chromium 75 和 Firefox 68 上测试,两者都没有saveAs.

工作原理似乎只是创建一个<a元素并使用 JavaScript 单击它哦,网络的恐怖。

这是一个演示,canvas.toBlob使用所选名称将生成的 blob 保存到您的下载文件夹mypng.png

var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
var pixel_size = 1;

function draw() {
    console.log("draw");
    for (x = 0; x < canvas.width; x += pixel_size) {
        for (y = 0; y < canvas.height; y += pixel_size) {
            var b = 0.5;
            ctx.fillStyle =
                "rgba(" +
                (x / canvas.width) * 255 + "," +
                (y / canvas.height) * 255 + "," +
                b * 255 +
                ",255)"
            ;
            ctx.fillRect(x, y, pixel_size, pixel_size);
        }
    }
    canvas.toBlob(function(blob) {
      saveAs(blob, 'mypng.png');
    });
}
window.requestAnimationFrame(draw);
<canvas id="my-canvas" width="512" height="512" style="border:1px solid black;"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js"></script>

这是下载多个图像的动画版本:将 HTML5 画布序列转换为视频文件

也可以看看:

@Michael 嗨,我已经在链接的答案中解决了这些问题:stackoverflow.com/questions/19235286/...摘要:保存前提示:无法避免第一个。等待帧保存:似乎不可能,我只是降低 FPS 并希望最好,这通常是不可接受的。
2021-04-28 02:33:40
另外,我怎么知道保存何时完成?现在我的代码甚至在我按 Enter 键保存之前就继续生成新的帧,但我需要保存每一帧。
2021-04-30 02:33:40
有什么方法可以避免在每次保存之前被提示吗?
2021-05-21 02:33:40

这里是直接的方式。


canvas.toBlob(function(blob){

    console.log(typeof(blob)) //let you have 'blob' here

    var blobUrl = URL.createObjectURL(blob);
    
    var link = document.createElement("a"); // Or maybe get it from the current document
    link.href = blobUrl;
    link.download = "image.jpg";
    link.innerHTML = "Click here to download the file";

    document.body.appendChild(link); // Or append it whereever you want
    document.querySelector('a').click() //can add an id to be specific if multiple anchor tag, and use #id

  }, 'image/jpeg', 1); // JPEG at 100% quality

花了一段时间来提出这个解决方案,如果这有帮助,请发表评论。感谢塞巴斯蒂安 C 的回答。

这个节点依赖更多的是 utils fs-web

npm i fs-web

用法

import * as fs from 'fs-web';

async processFetch(url, file_path = 'cache-web') {
    const fileName = `${file_path}/${url.split('/').reverse()[0]}`;
    let cache_blob: Blob;
    await fs.readString(fileName).then((blob) => {
      cache_blob = blob;
    }).catch(() => { });
    if (!!cache_blob) {
      this.prepareBlob(cache_blob);
      console.log('FROM CACHE');
    } else {
      await fetch(url, {
        headers: {},
      }).then((response: any) => {
        return response.blob();
      }).then((blob: Blob) => {
        fs.writeFile(fileName, blob).then(() => {
          return fs.readString(fileName);
        });
        this.prepareBlob(blob);
      });
 }

}

从文件选择器或输入类型=文件文件选择器,将文件名保存到本地存储:

HTML:

<audio id="player1">Your browser does not support the audio element</audio>

JavaScript:

function picksinglefile() {
    var fop = new Windows.Storage.Pickers.FileOpenPicker();
    fop.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.musicLibrary;
    fop.fileTypeFilter.replaceAll([".mp3", ".wav"]);
    fop.pickSingleFileAsync().then(function (file) {
        if (file) {
            // save the file name to local storage
            localStorage.setItem("alarmname$", file.name.toString());
        } else {
            alert("Operation Cancelled");
        }
    });
}

然后在你的代码中,当你想播放你选择的文件时,使用以下命令,它只使用音乐库中的名称来获取文件。(在 UWP 包清单中,将“功能”设置为包含“音乐库”。)

        var l = Windows.Storage.KnownFolders.musicLibrary;
        var f = localStorage.getItem("alarmname$").toString(); // retrieve file by name
        l.getFileAsync(f).then(function (file) {
            // storagefile file is available, create URL from it
            var s = window.URL.createObjectURL(file);
            var x = document.getElementById("player1");
            x.setAttribute("src", s);
            x.play();
        });