【问题标题】:Exporting file from Wasm memory to JS将文件从 Wasm 内存导出到 JS
【发布时间】:2020-03-10 20:16:04
【问题描述】:

我尝试创建一个 Wasm 模块,它将新生成的 ZIP 文件返回给 JavaScript(只是我自己项目的一个想法)。一切似乎都很好(源文件似乎在 Wasm 文件系统中正确分配,并由 zip library 处理),但我不确定如何正确将其传递给 JS。我想应该通过从 Wasm 内存返回一个 zip 文件指针及其字节长度,并使用它创建一个将转换为 Blob 的 bufferArray 来完成。有没有猜猜怎么做?

我正在使用emscripten 进行编译过程。

#include <fstream>
#include <iostream>
#include <emscripten.h>

#include "lib/zip.h"

using namespace std;

EM_JS(void, call_getZip, (filebuf * buf, size_t length), {
    // Call JS with pointer to buffer and buffer's length
    getZip(buf, length);
});

extern "C"
{
    ifstream file;

    void readFile(int *buffer, int length)
    {   
        // getFileName is a function that returnes file name from JS
        string fileName = getFileName(buffer, length);

        // Open file from WASM file system
        ifstream file;
        file.open("/" + fileName);

        filebuf *fbuf = file.rdbuf();
        size_t size = fbuf->pubseekoff(0, file.end, file.in);

        if (!file.is_open())
        {
            cout << "Failed to open file" << endl;
        }
        else
        {
            struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');

            zip_entry_open(zip, fileName.c_str());
            {
                zip_entry_write(zip, fbuf, size);
            }
            zip_entry_close(zip);
            zip_close(zip);

            ifstream zipFile;
            zipFile.open("foo.zip");

            if (zipFile.is_open())
            {
                cout << "Zip file exists!" << endl;

                filebuf *zipFileBuf = zipFile.rdbuf();

                // I assume this value will be equivalent to the length of allocated memory
                size_t zipFileSize = zipFileBuf->pubseekoff(0, file.end, file.in);

                call_getZip(zipFileBuf, size);
            }
            else
            {
                cout << "Problem with zip file?" << endl;
            }

            zipFile.close();
        }

        file.close();
    }
}

JavaScript:

function getZip(pointer, length) {
  // This approach doesn't work
  console.log(pointer, length);
  const buffer = new Uint32Array(Module.HEAP32, pointer, length);

  const fileUrl = URL.createObjectURL(
    new Blob([buffer], { type: "application/zip" })
  );

  const link = document.createElement("a");
  link.href = fileUrl;
  document.body.appendChild(link);
  link.click();
}
// ...

const file = fileInput.files[0];

const { buffer, length, free } = allocateFileName(file.name);

const fr = new FileReader();

fr.onload = function() {
const fileData = new Uint8Array(fr.result);

Module["FS_createDataFile"](
    "/",
    file.name,
    fileData,
    true,
    true,
    true
);

Module.ccall("readFile", ["number", "number"], "void", [
    buffer,
    length
]);

free();
// console.log(Module);
fileInput.value = null;
};

fr.readAsArrayBuffer(file);

非常感谢您提前提供的任何建议,我知道我在这里可能会犯一些愚蠢的错误,因此我会感谢任何线索和想法。

【问题讨论】:

    标签: javascript c++ emscripten webassembly


    【解决方案1】:

    与此同时,我找到了答案。感谢emscripten's File System API,在JS的wasm内存中get file contents超级方便:

    function getZip() {
      // "foo.zip" file name is for now hardcoded
      const content = FS.readFile("foo.zip", { encoding: "binary" });
    
      const fileUrl = URL.createObjectURL(
        new Blob(
          [new Uint8Array(content, content.byteOffset, content.length)],
          { type: " application/zip" }
        )
      );
    
      const link = document.createElement("a");
      link.href = fileUrl;
      link.innerHTML = "Click!";
      document.body.appendChild(link);
      link.click();
    }
    

    如果有人感兴趣,可以在this repo找到完整的工作代码。

    【讨论】:

      猜你喜欢
      • 2019-11-27
      • 1970-01-01
      • 2020-02-13
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      相关资源
      最近更新 更多