Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/450.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将客户端文件从前端传递到webassembly 我想把用户提交的数据传递给一个C++函数,我已经编译到WASM。数据是用户通过输入标签在前端提交的文件,如下所示: <input type="file" onChange={this.handleFile.bind(this)} />_Javascript_Html_C++_Webassembly - Fatal编程技术网

Javascript 将客户端文件从前端传递到webassembly 我想把用户提交的数据传递给一个C++函数,我已经编译到WASM。数据是用户通过输入标签在前端提交的文件,如下所示: <input type="file" onChange={this.handleFile.bind(this)} />

Javascript 将客户端文件从前端传递到webassembly 我想把用户提交的数据传递给一个C++函数,我已经编译到WASM。数据是用户通过输入标签在前端提交的文件,如下所示: <input type="file" onChange={this.handleFile.bind(this)} />,javascript,html,c++,webassembly,Javascript,Html,C++,Webassembly,最后,包含readFile函数的.cpp文件如下所示: handleFile(e){ const file = e.currentTarget.files[0]; const reader = new FileReader(); reader.onloadend = evt => { window.Module.readFile(evt.target.result); } reader.readAsArrayBuffer(file);

最后,包含readFile函数的.cpp文件如下所示:

handleFile(e){
    const file = e.currentTarget.files[0];
    const reader = new FileReader();
    reader.onloadend = evt => {
        window.Module.readFile(evt.target.result);
    }
    reader.readAsArrayBuffer(file);
}
void readFile(const std::string & rawString){
  std::vector<uint8_t> data(rawString.begin(), rawString.end());
  //...
}

EMSCRIPTEN_BINDINGS(my_module) {
  emscripten::function("readFile", &readFile);
}
void readFile(const std::string和rawString){
向量数据(rawString.begin(),rawString.end());
//...
}
EMSCRIPTEN_绑定(我的_模块){
emscripten::函数(“readFile”、&readFile);
}

我花了一下午的时间阅读各种文档,所以我知道我应该为堆上的这些文件分配内存,然后将ptr从js传递到readFile,而不是传递所有数据。我的问题是,我真的不明白这一切应该如何运作。有人能解释一下吗?

这是部分答案。它比我最初做的要好,我觉得它可能更接近创作者的意图。但是,我仍在创建文件的多个副本。归功于

这是我的handleFile回调,用我学到的东西进行了评论

handleFile(e){

    const file = e.currentTarget.files[0];
    if(!(file instanceof Blob)) return;
    const reader = new FileReader();
    reader.onloadend = evt => {

        //evt.target.result is an ArrayBuffer. In js, 
        //you can't do anything with an ArrayBuffer 
        //so we have to ???cast??? it to an Uint8Array
        const uint8_t_arr = new Uint8Array(evt.target.result);

        //Right now, we have the file as a unit8array in javascript memory. 
        //As far as I understand, wasm can't directly access javascript memory. 
        //Which is why we need to allocate special wasm memory and then
        //copy the file from javascript memory into wasm memory so our wasm functions 
        //can work on it.

        //First we need to allocate the wasm memory. 
        //_malloc returns the address of the new wasm memory as int32.
        //This call is probably similar to 
        //uint8_t * ptr = new uint8_t[sizeof(uint8_t_arr)/sizeof(uint8_t_arr[0])]
        const uint8_t_ptr = window.Module._malloc(uint8_t_arr.length);

        //Now that we have a block of memory we can copy the file data into that block
        //This is probably similar to 
        //std::memcpy(uint8_t_ptr, uint8_t_arr, sizeof(uint8_t_arr)/sizeof(uint8_t_arr[0]))
        window.Module.HEAPU8.set(uint8_t_arr, uint8_t_ptr);

        //The only thing that's now left to do is pass 
        //the address of the wasm memory we just allocated
        //to our function as well as the size of our memory.
        window.Module.readFile(uint8_t_ptr, uint8_t_arr.length);

        //At this point we're forced to wait until wasm is done with the memory. 
        //Your site will now freeze if the memory you're working on is big. 
        //Maybe we can somehow let our wasm function run on a seperate thread and pass a callback?

        //Retreiving our (modified) memory is also straight forward. 
        //First we get some javascript memory and then we copy the 
        //relevant chunk of the wasm memory into our javascript object.
        const returnArr = new Uint8Array(uint8_t_arr.length);
        //If returnArr is std::vector<uint8_t>, then is probably similar to 
        //returnArr.assign(ptr, ptr + dataSize)
        returnArr.set(window.Module.HEAPU8.subarray(uint8_t_ptr, uint8_t_ptr + uint8_t_arr.length));

        //Lastly, according to the docs, we should call ._free here.
        //Do we need to call the gc somehow?
        window.Module._free(uint8_t_ptr);

    }
    reader.readAsArrayBuffer(file);
}
handleFile(e){
const file=e.currentTarget.files[0];
如果(!(Blob文件实例))返回;
const reader=new FileReader();
reader.onloadend=evt=>{
//evt.target.result是js中的ArrayBuffer,
//你不能用ArrayBuffer做任何事
//所以我们必须把它放到一个UINT8阵列上
const uint8\u t\u arr=新的uint8数组(evt.target.result);
//现在,我们将该文件作为一个unit8array存储在javascript内存中。
//据我所知,wasm不能直接访问javascript内存。
//这就是为什么我们需要分配特殊的wasm内存,然后
//将文件从javascript内存复制到wasm内存中,这样我们的wasm函数
//我可以做。
//首先,我们需要分配wasm内存。
//_malloc将新wasm内存的地址返回为int32。
//这个电话可能类似于
//uint8_t*ptr=新uint8_t[sizeof(uint8_t_arr)/sizeof(uint8_t_arr[0])]
const uint8\u t\u ptr=窗口模块\u malloc(uint8\u t\u arr.length);
//既然我们有了一块内存,我们可以将文件数据复制到该块中
//这可能类似于
//标准::memcpy(uint8_t_ptr,uint8_t_arr,sizeof(uint8_t_arr)/sizeof(uint8_t_arr[0]))
window.Module.HEAPU8.set(uint8\u t\u arr,uint8\u t\u ptr);
//现在唯一要做的就是传球
//我们刚刚分配的wasm内存的地址
//我们的功能和记忆的大小。
window.Module.readFile(uint8_t_ptr,uint8_t_arr.length);
//在这一点上,我们不得不等到wasm处理完内存。
//如果您正在使用的内存很大,您的站点现在将冻结。
//也许我们可以让wasm函数在单独的线程上运行并传递回调?
//检索(修改过的)记忆也很简单。
//首先我们获得一些javascript内存,然后复制
//将wasm内存的相关块放入我们的javascript对象中。
const returnArr=新的uint8数组(uint8数组长度);
//如果returnArr是std::vector,则可能类似于
//returnArr.assign(ptr,ptr+dataSize)
returnArr.set(window.Module.HEAPU8.subarray(uint8_t_ptr,uint8_t_ptr+uint8_t_arr.length));
//最后,根据文件,我们应该打免费电话。
//我们需要打电话给gc吗?
无窗口模块(uint8\u t\u ptr);
}
reader.readAsArrayBuffer(文件);
}
这里是readFile.cpp

#include <emscripten/bind.h>

//We get out pointer as a plain int from javascript
void readFile(const int & addr, const size_t & len){
  //We use a reinterpret_cast to turn our plain int into a uint8_t pointer. After
  //which we can play with the data just like we would normally.
  uint8_t * data = reinterpret_cast<uint8_t *>(addr);
  for(size_t i = 0; i < len; ++i){
    data[i] += 1;
  }
}

//Using this command to compile
//  emcc --bind -O3 readFile.cpp -s WASM=1 -s TOTAL_MEMORY=268435456 -o api.js --std=c++11
//Note that you need to make sure that there's enough memory available to begin with.
//I got only 16mb without passing the TOTAL_MEMORY setting.
EMSCRIPTEN_BINDINGS(my_module) {
  emscripten::function("readFile", &readFile);
}
#包括
//我们从javascript中获取指针作为普通int
无效读取文件(常量int和addr、常量size\u t和len){
//我们使用reinterpret_cast将普通int转换为uint8_t指针
//我们可以像平常一样处理数据。
uint8\u t*数据=重新解释铸件(地址);
对于(尺寸i=0;i
使用Emscripten,您可以为WASM使用虚拟文件系统。 首先,使用
-sforce\u FILESYSTEM=1
选项编译C/C++代码。 在C/C++中,您只需像往常一样使用标准库函数处理文件。 在HTML页面上有一个
input type=file
元素

从输入元素获取文件并将其传递到WASM的示例JS代码:

function useFileInput(fileInput) {
    if (fileInput.files.length == 0)
        return;
    var file = fileInput.files[0];

    var fr = new FileReader();
    fr.onload = function () {
        var data = new Uint8Array(fr.result);

        Module['FS_createDataFile']('/', 'filename', data, true, true, true);
        Module.ccall('YourCppFunctionToUtilizeTheFile', null, [], null);

        fileInput.value = '';
    };
    fr.readAsArrayBuffer(file);
}
链接:


  • 可能的副本。我在另一个问题中提供的答案告诉您如何将字符串传入/传出WebAssembly。@JFBastien我不确定。昨天,我按照这些说明开始使用wasm->。当我编译一个.cpp文件时,我得到一个.js文件,我通过一个标记引用该文件,以访问全局范围内的模块对象。我一点也不确定你在做什么。你的做事方式是我应该做的吗?你能详细说明一下吗?