📝
(メモ)Rust で WebAssembly 上でファイルを作成したい
あわせて読みたい
ファイルを読む話は別の記事に書きました。
WASI の場合
読む場合と同じく、filesystem APIが使えるはず。
Node.js の場合
読む場合と同じく、fsモジュールが使えるはず。
ブラウザ上の場合
やりたいことは、作成したファイルをユーザーにレスポンスとして返したいわけですが、主に2つやり方があるようです。
まずひとつは、WebAssembly からはデータを丸ごと返して、それを Blob に変換する、というやり方です。このやり方は、わかりやすいですが、ぜんぶメモリ上に乗せないといけないので、重いファイルにはあまり向かないかもしれません(具体的にどれくらいのファイルサイズならいいのかは、勘所がなくてよくわかりません...)。あと、web worker 上で処理するのを前提にするなら、worker のスレッドからメインスレッドへのコピーのコストもあります。
もう一つは、Origin Private FileSystem(OPFS)に書き出す、という手です。
重いファイルの場合はたぶんこっちが向いているでしょう。ただし、読む場合と同じく、WebAssemblyでは非同期処理を扱えないので、同期処理を使うことになります。たぶんこの API が使えるはずです。
ChatGPT に書いてもらったコードによると(まだ試せてない)、web worker からはこんな感じで fileHandle を返して、
self.onmessage = async (event) => {
...
const opfsRoot = await navigator.storage.getDirectory();
const fileHandle = await opfsRoot.getFileHandle(filename, { create: true });
const syncHandle = await fileHandle.createSyncAccessHandle();
// syncHandle を介してデータを書き込む
self.postMessage(fileHandle);
};
main thread 側では、URL.createObjectURL() で URL をつくってそれをダウンロードさせる、みたいな感じになるようです。
const worker = new Worker('worker.js');
worker.onmessage = async (event) => {
const fileHandle = event.data;
const file = await fileHandle.getFile();
const url = URL.createObjectURL(file);
// この URL をダウンロードさせる
};
(タイトルに「Rust で」って書いたのに Rust の話ぜんぜん出てこなくてすみません...)
Discussion