コンテンツにスキップ
UniKVS
日本語
Esc
↑↓移動↵開く⌘Jプレビュー
このページの内容

@unikvs/opfs

ブラウザーの OPFS にバイト列を保存するストレージプラグインの使い方を説明します。

概要

@unikvs/opfs は、ブラウザーの OPFS(Origin Private File System)に保存するストレージプラグインです。データはバイト列(Uint8Array<ArrayBuffer>)専用です。ブラウザー専用

メインスレッド・Web Worker での動作を前提としています。

インストールは次のように行います。

npm install @unikvs/opfs
pnpm add @unikvs/opfs
yarn add @unikvs/opfs
bun add @unikvs/opfs
nub add @unikvs/opfs
aube add @unikvs/opfs

使い方

クラス名は Opfs です。デフォルト・名前付きのどちらでも取得できます。

import { Opfs } from "@unikvs/opfs";

const storage = new Opfs(".unikvs");

コンストラクター引数 root の型は string | FileSystemDirectoryHandle で、既定値は ".unikvs" です。文字列は OPFS 内のルート名、ハンドルは作業対象そのものとして扱います。ハンドルを渡すとオープン済み扱いです。第 2 引数 options は省略可能で、options.allowRepair(boolean、既定値 false)で書き戻しによる書き込みの許可を指定します。false の場合、書き戻し(vars["unikvs:repair"] が true)の write・getWritable はエラーを投げます。

使う前に open() を呼び出します。UniKvs と組み合わせる場合は、appendStorage で登録してから kvs.open() を呼びます。内部で Opfs.open() が呼ばれます。

import { UniKvs } from "unikvs";
import { Opfs } from "@unikvs/opfs";

const storage = new Opfs(".unikvs");
const kvs = UniKvs.config().appendStorage(storage).create();

await kvs.open();
// バイト列の読み書きを行います。
await kvs.close();

直接操作する場合は、write・read・exists・delete・clear を使います。いずれも事前の open() が必要です。

import { Opfs } from "@unikvs/opfs";

const storage = new Opfs(".unikvs");
await storage.open();

await storage.write({ key: "data.bin", data: new Uint8Array([1, 2, 3]) });
const data = await storage.read({ key: "data.bin" });
const found = await storage.exists({ key: "data.bin" });
await storage.delete({ key: "data.bin" });

ファイル配置

キーはファイル名として、指定ルートの直下に 1 対 1 で保存します。サブディレクトリーは作りません。キーは assertValidFilename で検証し、無効ならエラーになります。

文字列ルートは次の規則で正規化します。

  • ""・"."・"/" は空文字扱いで、OPFS ルート直下が作業対象になります。
  • 連続する / は 1 つにまとめ、先頭と末尾の / は取り除きます。
  • / で分割した各階層は assertValidDirname で検証します。

open() では navigator.storage.getDirectory() で起点を取得し、各階層を create: true で作成・取得します。clear() では、ルート直下なら各エントリーを個別に削除し、サブディレクトリーならごと削除して作り直します。

ストリーム

書き込み・読み取りの両ストリームに対応しています。

  • getWritable({ key, signal }) は WritableStream<Uint8Array<ArrayBuffer>> を返します。内部ではファイルハンドルから createWritable() で取得したストリームをライター経由で包みます。signal を中断すると書き込み途中の変更を破棄します。
  • getReadable({ key, signal }) は ReadableStream<Uint8Array<ArrayBuffer>> を返します。内部ではファイルを取得し、File.stream() をリーダー経由で包みます。signal を中断すると読み取りを中止し、以降の読み取りは中断理由で失敗します。
import { Opfs } from "@unikvs/opfs";

const storage = new Opfs(".unikvs");
await storage.open();

const writable = await storage.getWritable({ key: "large.bin" });
const writer = writable.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));
await writer.close();

const readable = await storage.getReadable({ key: "large.bin" });
await readable.cancel();

注意点

  • open() 前に read・write を行うと実行時エラーになります。必ず先にオープンしてください。
  • すべてのメソッドは signal を受け取ります。各操作は待機の区切りで signal を確認し、中断されていればその中断理由で失敗します。open が中断された場合は未オープンのままです。
  • write は失敗時に abort で変更を破棄するため、部分書き込みで既存データを壊しません。
  • exists は存在しないキーに false を返します。NotFoundError の DOMException を捕捉して判定し、それ以外は投げます。
  • キーとルート名にはファイル名の制約があります。無効な名前は検証エラーになります。

使用例

ブラウザーで Opfs を直接使用する最小例を示します。

import { Opfs } from "@unikvs/opfs";

const storage = new Opfs(".unikvs");
await storage.open();

const key = "hello.bin";
await storage.write({ key, data: new TextEncoder().encode("hello") });

const loaded = await storage.read({ key });
console.log(new TextDecoder().decode(loaded));
console.log(await storage.exists({ key }));

await storage.delete({ key });

このページは役に立ちましたか?