从 emscripten 读取用户提供的大文件,一次读取一大块

sc0*_*0ty 4 file-io emscripten html5-filesystem webassembly

我正在寻找一个 API,它可以让我一次读取通过(或允许从浏览器访问用户文件的任何其他方法)块提供的文件。我正在读取大文件,所以我不想将整个文件加载到内存中。

我的用例是,我正在使用用 emcc 编译的 ffmpeg 库,但我不想用它来处理多媒体文件。我可以实现自己的 AVIOContext,但要做到这一点,我需要相当于 C 函数 fread 和 fseek。

我正在查看具有 WORKERFS 文件系统类型的 FS API,但我不清楚是否可以使用 DOM 中的文件对象从工作线程挂载它。

sc0*_*0ty 5

我能够从工作线程使用 WORKERFS 挂载文件。

最小的例子:

主要.html:

<html>
<head>
<script>
    const worker = new Worker("worker.js");
    function onClick() {
        const f = document.getElementById("in-file").files[0];
        worker.postMessage([ f ]);
    }
</script>
</head>
<body>
    <input type="file" id="in-file" />
    <input type="button" onClick="onClick()" value="ok" />
</body>
</html>

Run Code Online (Sandbox Code Playgroud)

工人.js

onmessage = function(e) {
    const f = e.data[0];

    FS.mkdir('/work');
    FS.mount(WORKERFS, { files: [f] }, '/work');

    console.log(Module.read_file('/work/' + f.name));
}

self.importScripts('hello.js');

Run Code Online (Sandbox Code Playgroud)

hello.js 是用 ( emcc --bind -lworkerfs.js -o hello.js hello.cpp -s WASM=1) 编译的 hello.cpp:

#include <cstdio>
#include <string>
#include <iostream>
#include <fstream>
#include <emscripten/bind.h>
using namespace emscripten;

std::string read_file(const std::string &fn)
{
    std::ifstream f(fn);
    std::string line;
    std::getline(f, line);
    return line;
}

EMSCRIPTEN_BINDINGS(hello) {
    function("read_file", &read_file);
}
Run Code Online (Sandbox Code Playgroud)