Zenn
📁

バイナリをlocalStorageで管理したいと思っているそこのあなた、OPFSの出番ですよ!(AITuberサービスでのOPFS事例あり)

2025/03/08に公開
1

バイナリをlocalStorageに保存したいというケースは、特定の分野では意外とあります。
例えば、ちょっとした画像をサーバーではなくlocalStorageで保存して使いたい場合などです。
そういう場面では、OPFSを利用すると要件を満たせる可能性が高いです。

https://developer.mozilla.org/ja/docs/Web/API/File_System_API/Origin_private_file_system

そんな、意外と気軽に使えるOPFSについて、実際に私自身がAITuber関連サービスで活用している事例も含めて、Zennにまとめました。
もしOPFSに興味がある方は、ぜひご覧になってみてください。

1. OPFSとは?

OPFS(Origin Private File System)は、Webブラウザに組み込まれたファイルストレージAPIの一種です。

従来のlocalStorageIndexedDBとは異なり、バイナリデータを直接扱えるうえ、パフォーマンスに優れています 。

主な特徴は次のとおりです。

  • オリジン(ドメイン)ごとに管理されるプライベートなファイルシステム。ユーザーの実際のファイルシステムには現れず、Webサイトごとに隔離された領域として扱われます。
  • ユーザーの操作なしにデータを永続化できるlocalStorageのように明示的な容量警告はなく、許容量内であれば自動的に保存されます。(ただ容量の圧迫により削除される可能性あり。対応策は後述)
  • 大きなファイル(画像・動画など)の保存に適するlocalStorageのような数MB程度の容量制限がなく、ブラウザが許す限り大容量データを保存可能。
  • パフォーマンスの最適化:特殊な高速書き込み機構を持ち、ファイルへのインプレース(その場)書き込みができます (File System API - Web APIs | MDN)。
  • セキュリティとプライバシー:オリジンごとに隔離されているため、他サイトから内容を読み取られる心配がなく、またユーザーへの許可ダイアログも表示されません 。

「OPFS Explorer」拡張機能で確認したOPFS上のファイルシステムの例

これはChrome DevToolsの「OPFS Explorer」拡張機能で確認したOPFS上のファイルシステムの例です。ブラウザ内部に(Root)直下のフォルダやファイルを作成でき、ユーザーには見えない形で管理されます。

OPFSとlocalStorageの違い

項目 OPFS(オリジンプライベートファイルシステム) localStorage(ローカルストレージ)
データ構造 フォルダ・ファイルから成る仮想ファイルシステム キーと値(文字列)のペアによる保存
容量制限 大容量データの保存が可能(ブラウザごとの割当量に依存) 数MB程度で制限(ブラウザーはローカルストレージを 5MiB まで、オリジンごとにセッションストレージを 5MiB まで格納することが可能 - ブラウザーのストレージ制限と削除基準)
バイナリデータ 直接読み書き可能File/Blobそのまま保存) 不可(Base64エンコード等の変換が必要)
主な用途 画像・動画ファイルやSQLiteデータベースなど大容量データの永続化 設定情報やテキストなど小容量データの保存

上記のように、OPFSはブラウザ内にファイルシステムを作り出すイメージです。

例えば画像や動画、SQLiteのデータベースファイルなどもそのまま保存でき、localStorageでは扱えない大きなデータも格納できます

一方で、localStorageは手軽ですが容量が小さいため、設定値や小規模なユーザーデータの保存程度の用途に留まります。

2. OPFSを使った画像保存の基本実装

では、実際にブラウザ側で画像データをOPFSに保存する基本的なコードを紹介します。ユーザーが選択した画像ファイル(例えば<input type="file">で取得したFileオブジェクト)をOPFSに保存する例です。

async function saveImageToOPFS(file) {
  // OPFSのルートディレクトリにアクセス
  const root = await navigator.storage.getDirectory();
  
  // 保存用のファイルハンドルを取得(なければ作成)
  const fileHandle = await root.getFileHandle('saved_image.png', { create: true });
  
  // 書き込み用ストリームを開く
  const writable = await fileHandle.createWritable();
  
  // ファイルデータ(画像)を書き込む
  await writable.write(file);
  
  // ストリームを閉じて保存を確定
  await writable.close();
}

このコードにより、選択した画像データがブラウザ内のストレージに保存されます。getFileHandleでファイル名を指定し、create: trueオプションで存在しない場合は新規作成します。createWritable()で書き込みストリームを取得し、write()メソッドにFileBlobを渡すことで、バイナリデータを直接書き込めます。

最後にclose()することでデータが確定し、ローカルに保存されます。

3. OPFSの制約と注意点

OPFSは便利な反面、いくつか注意すべき点や制約があります。主にブラウザごとの対応状況ストレージ容量に関する点です。

(1) SafariやFirefoxのサポート状況

現時点ではSafari(WebKit)やFirefoxではOPFSの一部機能が未対応のため、クロスブラウザで利用する際は注意が必要です。 SafariやFirefoxではFileSystemFileHandle.createWritable()メソッドが実装されておらず、上記コードのままでは動作しません。

そのため、これらのブラウザでは代替としてWeb Worker内で同期アクセスハンドル(createSyncAccessHandle())を使う方法などを検討する必要があります。

また、ブラウザ各社の対応状況は変化するため、最新の情報はMDNのAPI対応状況表などで確認してください。

(2) ストレージ容量の制限

OPFS自体にはlocalStorageのような明確なサイズ上限(5MB程度)はありませんが、ブラウザごとのストレージクォータ制限の影響を受けます。

https://developer.mozilla.org/ja/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria

各ブラウザは、使用状況に応じてサイトごとのストレージ最大容量を決定しており、上限に達するとQuotaExceededErrorが発生します。

例えばChromeでは利用可能なディスク容量の一定割合まで使用できると言われています。一方、プライベートブラウジングモードでは保存容量が揮発的になるなどの違いもあります。

大量のデータを保存する場合でも、navigator.storage.estimate()で残り容量を確認したり、必要に応じてnavigator.storage.persist()で永続ストレージへの昇格を要求することが推奨されます。

OPFS はそのような問題をどのように解決するのか - MDN

4. AITuber OnAirでの活用事例

実際のWebアプリケーションでのOPFS活用例として、AITuber OnAirというサービスがあります。これは現在進行形で私自身が開発しているもので、OPFSの機能を活用しながらシステムを構築しています。
(これは紛れもない宣伝です。AITuberに興味がある方は是非お見知りおきを)

https://aituberonair.com/

※使い方については以下をご覧ください

https://note.com/aituberonair/n/n39b30eb3eb5b

AITuber OnAirでは、ユーザーがアップロードした画像データやVTuber用アバターファイル(VRM)、さらにフロントエンドだけで動作するデータベース(SQLite Wasm)のファイルをOPFSに保存して管理しています。

つまり、配信に使う各種データをサーバーに送信せずユーザーのブラウザ内に留めているのです。

サーバーにデータを置かないことで、ユーザープライバシーの保護や通信遅延の低減といったメリットがあります(ブラウザ内で完結しているため処理は高速です)。

また、サーバーをあまり必要としないため、固定費の削減やサーバー管理リソースの軽減など、運用面でも一定の効果があります。

さらには、SQLite WasmによるローカルデータベースもOPFSに保存することで、完全にフロントエンド(ブラウザ内)だけでデータ管理を簡潔化させることが可能になっています。

このように、AITuber OnAirは「ブラウザだけで配信準備が完結できる」ことを強みとしており、OPFSがそのキー技術となっています。

実際、ブラウザに一度保存された画像やアバターデータを繰り返し利用できるため、セットアップの高速化やサーバーコスト削減にもつながっています。

5. まとめ

OPFSを利用することで、画像データなど大きなバイナリファイルをブラウザ側で安全かつ効率的に保存することが可能です。localStorageや従来の方法では困難だったシナリオでも、OPFSなら以下のような利点があります。

  • ブラウザ内にファイルシステム構造を持つストレージを実現し、フォルダ分けや大容量データの管理が容易。
  • 画像・動画ファイルやWebAssembly経由のデータベース (SQLite Wasmなど) を含め、大容量のデータを効率よく永続化できます。
  • ただし、Safariなど一部ブラウザの対応状況やストレージ容量の上限には注意が必要です。必要に応じてフォールバック実装や容量確認を行いましょう。
  • OPFSとSQLite Wasmを組み合わせることで、サーバーに依存しない完全フロントエンドのデータ管理(オフラインファーストなアプリ)が現実的になります

ちなみに、OPFSと SQLite Wasm の組み合わせについては以前にもZennで記事を書いています。
よろしければ、あわせてご覧ください。
(今回紹介したAITuber OnAirの仕組みも、ここで考えていた構成を発展させた形です)

https://zenn.dev/shinshin86/articles/fdf4cbe40b2bad

もしブラウザ上で画像データをローカル管理したいと考えているなら、OPFSの活用は非常に有力な選択肢です。

その際は本記事で触れたポイント(ブラウザ互換性や容量制限)に留意しつつ、ぜひ実際に試してみてください。

最新のブラウザではOPFSがサポートされつつあり、ウェブアプリの可能性を大きく広げています。

1

Discussion

ログインするとコメントできます