我尝试创建一个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);
非常感谢您的任何建议,我知道我在这里可能犯了一些愚蠢的错误,因此,我将感谢您提供的任何线索和想法。
答案 0 :(得分:0)
与此同时,我找到了答案。多亏了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中找到完整的工作代码。