. JavaScript】File System Access API – ディレクトリを開く方法 showDirectoryPicker() 編 –
JavaScript】File System Access API – ディレクトリを開く方法 showDirectoryPicker() 編 –
JavaScript】File System Access API – ディレクトリを開く方法 showDirectoryPicker() 編 –

【JavaScript】File System Access API – ディレクトリを開く方法 showDirectoryPicker() 編

File System Access API にはファイルを開く showOpenFilePicker() メソッド、ファイル保存ダイアログを表示する showSaveFilePicker() メソッドが用意されています。一つのファイルの読み書きであればこれらで十分です。しかしディレクトリを開いて、その下部のファイルやディレクトリに自由にアクセスしたい場合もあるでしょう。その場合、1 つのファイルにアクセスするたびにファイルピッカーが開くのは煩わしいと感じるはずです。それを解決するのが showDirectoryPicker() メソッドです。

これらのケースは、Microsoft Visual Studio Code といった開発用テキストエディタでプロジェクトディレクトリを開くことを想像すると分かりやすいでしょう。今回は、そのようなディレクトリアクセスについて解説します。

  1. showDirectoryPicker() メソッドでディレクトリを開く
  2. ディレクトリ内の操作
  3. 選択ディレクトリの保存とユーザーの許可
  4. まとめ

showDirectoryPicker() メソッドでディレクトリを開く

showDirectoryPicker() メソッドは window オブジェクトのメソッドで Promise オブジェクトを返します。次の例は button 要素のボタンをクリックしたら、ディレクトリ選択ダイアログを表示します。ユーザーがディレクトリを選択したら、その直下にあるファイルとディレクトリの名前をコンソールに出力します。

< // ディレクトリ選択ダイアログを表示して // FileSystemDirectoryHandle オブジェクトを取得 const dh = await window.showDirectoryPicker(); // 開いたディレクトリ内のファイルとディレクトリをコンソールに出力 for await (const handle of root.values()) < if (handle.kind === 'file') < console.log(handle.name); >else if (handle.kind === 'directory') < console.log(handle.name + '/'); >> >);

ユーザーが「キャンセル」ボタンを押すと、 showDirectoryPicker() メソッドは DOMException 例外を投げます。そして、ユーザーが「フォルダーの選択」ボタンを押すと次のような許可ダイアログをが表示されます。

ユーザーがこの許可ダイアログの「キャンセル」ボタンを押すと、 showDirectoryPicker() メソッドは DOMException 例外を投げます。そして、ユーザーが「ファイルを表示する」を押すと、 showDirectoryPicker() メソッドはユーザーが選択したディレクトリを表す FileSystemDirectoryHandle オブジェクト(変数 dh )を返します。

images/ test.html

ディレクトリ内の操作

showDirectoryPicker() メソッドでディレクトリを開くと、ブラウザーを閉じない限り、そのディレクトリ内であれば、ファイル操作を自由に行うことができます。次のサンプルは、開いたディレクトリ直下にある index.html の内容を読み取ってから、まったく別の内容に書き換えます。

このサンプルでは、index.html に書き込みを行おうとすると、次のような許可ダイアログが表示されます。「変更を保存」を押すと、実際に index.html が書き換えられます。

選択ディレクトリの保存とユーザーの許可

しかし、File System Access API では選択されたディレクトリのパスを知ることはできません。仮にそのパスが分かったところで、そのパス情報からディレクトリを自動的い開く手段も用意されていません。しかし、一度ユーザーが選択したディレクトリを表す FileSystemDirectoryHandle オブジェクトが手に入ればどうでしょう。このオブジェクトさえ手に入れば、そのディレクトリ配下は自由に操作できるはずです。

実は、 FileSystemDirectoryHandle オブジェクトはシリアル化可能オブジェクト(Serializable object)になっています。 FileSystemDirectoryHandle オブジェクトだけでなく、ファイルを表す FileSystemFileHandle もシリアル化可能オブジェクトです。シリアル化可能オブジェクトは JSON などのテキストに変換できるというわけではありませんが、Indexed Database API の値としてストレージに保存することが可能なのです。

Indexed Database API は少し複雑なので、Web Storage のように Key-Value でデータを Indexed Database API に保存できる JS ライブラリー「IDB-Keyval」を使って、コードを見てみましょう。

< // Indexed Database から FileSystemDirectoryHandle オブジェクトを取得 // なければディレクトリ選択ダイアログを表示 let dh = await idbKeyval.get('dir'); if (!dh) < dh = await window.showDirectoryPicker(); >// ファイルとディレクトリの一覧 for await (const handle of dh.values()) < if (handle.kind === 'file') < console.log(handle.name); >else if (handle.kind === 'directory') < console.log(handle.name + '/'); >> // FileSystemDirectoryHandle オブジェクトを Indexed Database に保存 await idbKeyval.set('dir', dh); >);

このサンプルは、ボタンがクリックされたら Indexed Database から FileSystemDirectoryHandle オブジェクトを取得します。なければ、 showDirectoryPicker() を呼び出し、ユーザーにディレクトリを選択させて FileSystemDirectoryHandle オブジェクトを取得します。

ディレクトリハンドルが取得できたら、そのディレクトリ直下のファイルやディレクトリの名前をコンソールに出力し、最後に、ディレクトリハンドルである FileSystemDirectoryHandle オブジェクトを Indexed Database に保存します。

Uncaught (in promise) DOMException: The request is not allowed by the user agent or the platform in the current context.

二回目のアクセスでは、Indexed Database に保存された FileSystemDirectoryHandle オブジェクトを使い回すことになります。もしこのコードが機能してしまうと、ユーザーに何も知らせないままディレクトリにアクセスできてしまうことになります。

File System Access API では、このようなケースに対処するべく、ユーザーの許可がすでに得られているのかを調べるメソッドと、ユーザーの許可を得るメソッドを用意しています。前述のサンプルを修正すると、次のようになります。

document.getElementById('btn3').addEventListener('click', async () => < // Indexed Database から FileSystemDirectoryHandle オブジェクトを取得 let dh = await idbKeyval.get('dir'); if (dh) < // すでにユーザーの許可が得られているかをチェック let permission = await dh.queryPermission(< mode: 'readwrite' >); if (permission !== 'granted') < // ユーザーの許可が得られていないなら、許可を得る(ダイアログを出す) permission = await dh.requestPermission(< mode: 'readwrite' >); if (permission !== 'granted') < throw new Error('ユーザーの許可が得られませんでした。'); >> > else < // ディレクトリ選択ダイアログを表示 dh = await window.showDirectoryPicker(); >// ファイルとディレクトリの一覧 for await (const handle of dh.values()) < if (handle.kind === 'file') < console.log(handle.name); >else if (handle.kind === 'directory') < console.log(handle.name + '/'); >> // FileSystemDirectoryHandle オブジェクトを Indexed Database に保存 await idbKeyval.set('dir', dh); >);

このコードでは、Indexed Database から FileSystemDirectoryHandle オブジェクトが得られたら、まずユーザーの許可が得られているかをチェックしています。

let permission = await dh.queryPermission(< mode: 'readwrite' >);

FileSystemDirectoryHandle オブジェクト(変数 dh )の queryPermission() メソッドを使って、ユーザーの許可の状況を得ます。 queryPermission() に引き渡した mode プロパティには "read" か "readwrite" を指定することができます。デフォルト値は "read" です。ここでは "readwrite" を指定していますので、読み取りだけでなく書き込みの権限もチェックすることになります。

queryPermission() メソッドは "granted" , "denied" , "prompt" のいずれかを返します。ユーザーがすでに許可済みかをチェックしたいだけなら、その値が "granted" かどうかをチェックします。

permission = await dh.requestPermission(< mode: 'readwrite' >);

FileSystemDirectoryHandle オブジェクト(変数 dh )の requestPermission() メソッドを呼び出すと、ユーザーに許可ダイアログを表示します。

ユーザーが「変更を保存」を押せば requestPermission() メソッドは "granted" を返します。「キャンセル」を押せば "prompt" を返します。

まとめ

ユーザーが選択したディレクトリ配下を自由にアクセスできることで、ウェブアプリはデスクトップアプリにかなり近づいた感じがしないでしょうか。Microsoft 365、Google ドキュメント・スプレッドシート・スライド、Adobe のウェブ版 Photoshop・Illustrator など、デスクトップアプリと同じことがブラウザー上で実現できるようになっています。

2022 年 6 月現在、 showDirectoryPicker() メソッドをサポートしているのは Chrome や Edge などの Chromium 系ブラウザーに限られますが、ローカルファイルやディレクトリへのアクセスが自由になることで、ウェブアプリ化がどんどん進んでいくのではないかと期待せずにいられません。

2022年6月12日 by ninja JavaScript

名無しの ninja です。このブログの管理人です。プロフィールはこちらへ https://webfrontend.ninja/profile/

You may also like. 【JavaScript】File System Access API – 仮想的なファイルシステム Origin Private File System 編 【HTML】section 要素を見つめなおす 【JavaScript】ブラウザーで OpenAI API の音声認識 (Speech to Text) でマイク音声を録音してアップロードする方法

webfrontend.ninja © 2026. All Rights Reserved.

📎📎📎📎📎📎📎📎📎📎