在 Blazor 中保存使用 Cs 创建的大文件

Save large file created with Cs in Blazor

我正在做一个周末项目,该项目使用 Blazor (webassmbly) 将来自其他站点的下载汇总到一个 zip 文件中。

zip 文件是用 c# 代码创建的,需要保存在本地计算机上。我使用的是 的修改版本,因为文件大小很容易超过 400 mb。

我的版本对 js 调用进行了分区,使其不会立即溢出 webassembly VM,但在达到一定的文件大小后,它发生了,我得到了以下异常:

WASM: Try saving 213776418bytes --my message
blazor.webassembly.js:1 WASM: GC_MAJOR_SWEEP: major size: 1808K in use: 94964K
blazor.webassembly.js:1 WASM: GC_MAJOR: (LOS overflow) time 71.98ms, stw 72.00ms los size: 486832K in use: 481083K
WASM: Error: Garbage collector could not allocate 16384 bytes of memory for major heap section.
Uncaught (in promise) ExitStatus {name: "ExitStatus", message: "Program terminated with exit(1)", status: 1}

除了将文件内容传输到 js 然后用 Blob 保存之外,目前还有其他方法可以从 WebAssembly 保存文件吗?

我找到了解决办法。随着 .Net5 的最新更新,现在可以使用 IJSUnmarshalledRuntime。这使一切变得容易得多。请注意,似乎仍然存在限制或其他限制我被迫将我的文件分区到大约 200mb,但解决方案非常快并且似乎工作得“很好”。警告:仅适用于 Webassembly Blazor!

首先使用 FileUtil 编写:

public static class FileUtil
{
    public static void SaveAs(this IJSRuntime js, string filename, MemoryStream data)
    {
        var rt = js as IJSUnmarshalledRuntime;
        var dataArray = data.ToArray();
        rt.InvokeUnmarshalled<string, byte[], object>(
            "saveAsFile",
            filename,
            dataArray);
    }
}

然后使用这个js函数:

function saveAsFile(filenamePointer, contentPointer) {
    var parts = Blazor.platform.toUint8Array(contentPointer);
    var filename = BINDING.conv_string(filenamePointer);

    var blob = new Blob([parts], { type: "application/octet-stream" });
    if (navigator.msSaveBlob) {
        //Download document in Edge browser
        navigator.msSaveBlob(blob, filename);
    }
    else {
        var link = document.createElement('a');
        link.download = filename;
        link.href = URL.createObjectURL(blob);
        document.body.appendChild(link); // Needed for Firefox
        link.click();
        document.body.removeChild(link);
    }
}