File System Access API: ローカル ファイルへのアクセスを簡素化

File System Access API を使用すると、ウェブアプリはユーザーのデバイス上のファイルやフォルダに変更を直接読み取ったり保存したりできます。

File System Access API を使用すると、デベロッパーは、IDE、写真や動画のエディタ、テキスト エディタなど、ユーザーのローカル デバイス上のファイルとやり取りする強力なウェブアプリを構築できます。ユーザーがウェブアプリにアクセス権を付与すると、この API を使用して、ユーザーのデバイス上のファイルやフォルダに変更を直接読み取ったり保存したりできるようになります。File System Access API では、ファイルを読み書きするだけでなく、ディレクトリを開いて内容を列挙することもできます。

ファイルの読み取りと書き込みを扱ったことがある場合は、これから説明する内容の多くは馴染みがあるでしょう。すべてのシステムに同じものはないので、いずれにしても読んでおくことをおすすめします。

File System Access API は、Windows、macOS、ChromeOS、Linux のほとんどの Chromium ブラウザでサポートされています。例外として、Brave は現在、フラグありの場合のみ利用可能です。Android のサポートは、crbug.com/1011535 のコンテキストで現在開発中です。

File System Access API の使用

File System Access API のパワーと有用性を示すために、1 つのファイルテキスト エディタを作成しました。テキスト ファイルを開いて編集し、変更をディスクに保存できます。また、新しいファイルを作成して変更をディスクに保存することもできます。特別なものではありませんが、コンセプトの理解に役立ちます。

ブラウザ サポート

対応ブラウザ

  • Chrome: 86。
  • Edge: 86。
  • Firefox: サポートされていません。
  • Safari: サポートされていません。

ソース

機能検出

File System Access API がサポートされているかどうかを確認するには、目的の選択ツール メソッドが存在するかどうかを確認します。

if ('showOpenFilePicker' in self) {
  // The `showOpenFilePicker()` method of the File System Access API is supported.
}

試してみる

テキスト エディタのデモで File System Access API の実際の動作を確認する。

ローカル ファイル システムからファイルを読み取る

最初に取り組むユースケースでは、ユーザーにファイルを選択してもらい、そのファイルを開いてディスクから読み取ります。

読み取るファイルを選択するようユーザーに依頼する

File System Access API のエントリ ポイントは window.showOpenFilePicker() です。呼び出されると、ファイル選択ツールのダイアログが表示され、ユーザーにファイルの選択を求めます。ファイルを選択すると、API はファイルハンドルの配列を返します。オプションの options パラメータを使用すると、ファイル選択ツールの動作を変更できます。たとえば、ユーザーが複数のファイル、ディレクトリ、または異なるファイルタイプを選択できるようにします。オプションを指定しないと、ファイル選択ツールでユーザーは 1 つのファイルを選択できます。これはテキスト エディタに最適です。

他の多くの強力な API と同様に、showOpenFilePicker() の呼び出しは安全なコンテキストで実行し、ユーザー操作内から行う必要があります。

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  // Destructure the one-element array.
  [fileHandle] = await window.showOpenFilePicker();
  // Do something with the file handle.
});

ユーザーがファイルを選択すると、showOpenFilePicker() はハンドルの配列を返します。この場合、ファイルの操作に必要なプロパティとメソッドを含む 1 つの FileSystemFileHandle を含む 1 要素の配列です。

後で使用できるように、ファイル ハンドルへの参照を保持しておくと便利です。ファイルへの変更を保存したり、他のファイル オペレーションを実行したりする際に必要になります。

ファイル システムからファイルを読み取る

ファイルへのハンドルを取得したので、ファイルのプロパティを取得したり、ファイル自体にアクセスしたりできます。内容をお読みします。handle.getFile() を呼び出すと、BLOB を含む File オブジェクトが返されます。Blob からデータを取得するには、そのメソッドslice()stream()text()arrayBuffer())のいずれかを呼び出します。

const file = await fileHandle.getFile();
const contents = await file.text();

FileSystemFileHandle.getFile() によって返される File オブジェクトは、ディスク上の基盤となるファイルが変更されていない場合にのみ読み取ることができます。ディスク上のファイルが変更されると、File オブジェクトは読み取り不能になり、変更されたデータを読み取るために新しい File オブジェクトを取得するために getFile() を再度呼び出す必要があります。

すべてを組み合わせる

ユーザーが [開く] ボタンをクリックすると、ブラウザにファイル選択ツールが表示されます。ファイルを選択すると、アプリは内容を読み取り、<textarea> に格納します。

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const contents = await file.text();
  textArea.value = contents;
});

ファイルをローカル ファイル システムに書き込む

テキスト エディタでファイルを保存するには、[保存] と [名前を付けて保存] の 2 つの方法があります。保存: 前に取得したファイルハンドルを使用して、変更を元のファイルに書き込みます。ただし、[名前を付けて保存] では新しいファイルが作成されるため、新しいファイルハンドルが必要になります。

新しいファイルを作成する

ファイルを保存するには、showSaveFilePicker() を呼び出します。これにより、ファイル選択ツールが「保存」モードで表示され、保存に使用する新しいファイルをユーザーが選択できるようになります。また、テキスト エディタでは、.txt 拡張機能が自動的に追加されるようにするため、追加のパラメータを指定しました。

async function getNewFileHandle() {
  const options = {
    types: [
      {
        description: 'Text Files',
        accept: {
          'text/plain': ['.txt'],
        },
      },
    ],
  };
  const handle = await window.showSaveFilePicker(options);
  return handle;
}

ディスクに変更を保存する

ファイルへの変更を保存するコードはすべて、GitHubテキスト エディタのデモで確認できます。コア ファイル システムのインタラクションは fs-helpers.js にあります。最も単純なプロセスは次のコードのようになります。手順を順に説明します。

// fileHandle is an instance of FileSystemFileHandle..
async function writeFile(fileHandle, contents) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Write the contents of the file to the stream.
  await writable.write(contents);
  // Close the file and write the contents to disk.
  await writable.close();
}

ディスクにデータを書き込むには、WritableStream のサブクラスである FileSystemWritableFileStream オブジェクトを使用します。ファイル ハンドル オブジェクトで createWritable() を呼び出して、ストリームを作成します。createWritable() が呼び出されると、ブラウザはまず、ユーザーがファイルへの書き込み権限を付与しているかどうかを確認します。書き込み権限が付与されていない場合、ブラウザはユーザーに権限を求めます。権限が付与されていない場合、createWritable()DOMException をスローし、アプリはファイルに書き込めなくなります。テキスト エディタでは、DOMException オブジェクトは saveFile() メソッドで処理されます。

write() メソッドは文字列を受け取ります。これはテキスト エディタに必要なものです。ただし、BufferSource または Blob を受け取ることもできます。たとえば、ストリームを直接パイプできます。

async function writeURLToFile(fileHandle, url) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Make an HTTP request for the contents.
  const response = await fetch(url);
  // Stream the response into the file.
  await response.body.pipeTo(writable);
  // pipeTo() closes the destination pipe by default, no need to close it.
}

ストリーム内で seek() または truncate() を使用して、特定の位置でファイルを更新したり、ファイルのサイズを変更したりすることもできます。

推奨されるファイル名と開始ディレクトリを指定する

多くの場合、アプリでデフォルトのファイル名や場所の候補を表示できます。たとえば、テキスト エディタでは、Untitled ではなく Untitled Text.txt というデフォルトのファイル名を提案できます。これを行うには、showSaveFilePicker オプションの一部として suggestedName プロパティを渡します。

const fileHandle = await self.showSaveFilePicker({
  suggestedName: 'Untitled Text.txt',
  types: [{
    description: 'Text documents',
    accept: {
      'text/plain': ['.txt'],
    },
  }],
});

デフォルトの start ディレクトリについても同様です。テキスト エディタを作成する場合は、ファイルの保存またはファイルを開くダイアログをデフォルトの documents フォルダで開始し、イメージ エディタの場合はデフォルトの pictures フォルダから開始することをおすすめします。デフォルトの開始ディレクトリを提案するには、startIn プロパティを showSaveFilePickershowDirectoryPicker()、または showOpenFilePicker メソッドに渡します。

const fileHandle = await self.showOpenFilePicker({
  startIn: 'pictures'
});

よく知られているシステム ディレクトリのリストは次のとおりです。

  • desktop: ユーザーのデスクトップ ディレクトリ(存在する場合)。
  • documents: 通常、ユーザーが作成したドキュメントが保存されるディレクトリ。
  • downloads: ダウンロードされたファイルが通常保存されるディレクトリ。
  • music: 通常、音声ファイルが保存されるディレクトリ。
  • pictures: 写真などの静止画像が通常保存されるディレクトリ。
  • videos: 通常、動画や映画が保存されるディレクトリ。

既知のシステム ディレクトリ以外にも、既存のファイル ハンドルまたはディレクトリ ハンドルを startIn の値として渡すこともできます。ダイアログが同じディレクトリで開きます。

// Assume `directoryHandle` is a handle to a previously opened directory.
const fileHandle = await self.showOpenFilePicker({
  startIn: directoryHandle
});

さまざまなファイル選択ツールの目的を指定する

アプリには、目的ごとに異なる選択ツールが用意されている場合があります。たとえば、リッチテキスト エディタでは、ユーザーがテキスト ファイルを開くだけでなく、画像をインポートすることもできます。デフォルトでは、各ファイル選択ツールは最後に記憶された場所で開きます。この問題を回避するには、各タイプの選択ツールの id 値を保存します。id が指定されている場合、ファイル選択ツールの実装では、その id の最後に使用したディレクトリが別途記憶されます。

const fileHandle1 = await self.showSaveFilePicker({
  id: 'openText',
});

const fileHandle2 = await self.showSaveFilePicker({
  id: 'importImage',
});

IndexedDB にファイルハンドルまたはディレクトリ ハンドルを保存する

ファイルハンドルとディレクトリ ハンドルはシリアル化できます。つまり、ファイルハンドルまたはディレクトリ ハンドルを IndexedDB に保存したり、postMessage() を呼び出して同じトップレベルのオリジン間で送信したりできます。

ファイルまたはディレクトリのハンドルを IndexedDB に保存すると、状態を保存したり、ユーザーが作業していたファイルやディレクトリを記憶したりできます。これにより、最近開いたファイルや編集したファイルのリストを保持したり、アプリを開いたときに最後に開いたファイルを再び開くよう提案したり、以前の作業ディレクトリを復元したりできます。テキスト エディタには、ユーザーが開いた直近の 5 つのファイルのリストを保存し、それらのファイルに再度アクセスできるようにします。

次のコード例は、ファイル ハンドルとディレクトリ ハンドルの保存と取得を示しています。この機能の動作は Glitch で確認できます。(簡潔にするため、idb-keyval ライブラリを使用しています)。

import { get, set } from 'https://unpkg.com/idb-keyval@5.0.2/dist/esm/index.js';

const pre1 = document.querySelector('pre.file');
const pre2 = document.querySelector('pre.directory');
const button1 = document.querySelector('button.file');
const button2 = document.querySelector('button.directory');

// File handle
button1.addEventListener('click', async () => {
  try {
    const fileHandleOrUndefined = await get('file');
    if (fileHandleOrUndefined) {
      pre1.textContent = `Retrieved file handle "${fileHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const [fileHandle] = await window.showOpenFilePicker();
    await set('file', fileHandle);
    pre1.textContent = `Stored file handle for "${fileHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

// Directory handle
button2.addEventListener('click', async () => {
  try {
    const directoryHandleOrUndefined = await get('directory');
    if (directoryHandleOrUndefined) {
      pre2.textContent = `Retrieved directroy handle "${directoryHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const directoryHandle = await window.showDirectoryPicker();
    await set('directory', directoryHandle);
    pre2.textContent = `Stored directory handle for "${directoryHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

保存されているファイルまたはディレクトリのハンドルと権限

権限はセッション間で保持されない場合があります。そのため、ユーザーがファイルまたはディレクトリに対する権限を付与しているかどうかを queryPermission() を使用して確認する必要があります。まだ取得していない場合は、requestPermission() に電話して(再)リクエストします。これは、ファイル ハンドルとディレクトリ ハンドルでも同様に機能します。fileOrDirectoryHandle.requestPermission(descriptor) または fileOrDirectoryHandle.queryPermission(descriptor) をそれぞれ実行する必要があります。

テキスト エディタで、ユーザーがすでに権限を付与しているかどうかを確認し、必要に応じてリクエストを行う verifyPermission() メソッドを作成しました。

async function verifyPermission(fileHandle, readWrite) {
  const options = {};
  if (readWrite) {
    options.mode = 'readwrite';
  }
  // Check if permission was already granted. If so, return true.
  if ((await fileHandle.queryPermission(options)) === 'granted') {
    return true;
  }
  // Request permission. If the user grants permission, return true.
  if ((await fileHandle.requestPermission(options)) === 'granted') {
    return true;
  }
  // The user didn't grant permission, so return false.
  return false;
}

読み取りリクエストで書き込み権限をリクエストすることで、権限プロンプトの数を減らしました。ユーザーはファイルを開くときに 1 つのプロンプトが表示され、読み取りと書き込みの両方の権限を付与します。

ディレクトリを開いて内容を列挙する

ディレクトリ内のすべてのファイルを列挙するには、showDirectoryPicker() を呼び出します。ユーザーが選択ツールでディレクトリを選択すると、FileSystemDirectoryHandle が返されます。これにより、ディレクトリのファイルを列挙してアクセスできます。デフォルトでは、ディレクトリ内のファイルへの読み取りアクセス権が付与されますが、書き込みアクセス権が必要な場合は、メソッドに { mode: 'readwrite' } を渡すことができます。

butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  for await (const entry of dirHandle.values()) {
    console.log(entry.kind, entry.name);
  }
});

個々のファイルサイズを取得するために getFile() を使用して各ファイルにアクセスする必要がある場合は、各結果に対して await を順次使用するのではなく、Promise.all() を使用して、すべてのファイルを並行して処理します。

butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  const promises = [];
  for await (const entry of dirHandle.values()) {
    if (entry.kind !== 'file') {
      continue;
    }
    promises.push(entry.getFile().then((file) => `${file.name} (${file.size})`));
  }
  console.log(await Promise.all(promises));
});

ディレクトリ内のファイルやフォルダの作成またはアクセス

ディレクトリから、getFileHandle() または getDirectoryHandle() メソッドを使用して、ファイルやフォルダを作成したり、それらにアクセスしたりできます。キーが create でブール値が true または false の省略可能な options オブジェクトを渡すことで、新しいファイルまたはフォルダが存在しない場合、作成するかどうかを判断できます。

// In an existing directory, create a new directory named "My Documents".
const newDirectoryHandle = await existingDirectoryHandle.getDirectoryHandle('My Documents', {
  create: true,
});
// In this new directory, create a file named "My Notes.txt".
const newFileHandle = await newDirectoryHandle.getFileHandle('My Notes.txt', { create: true });

ディレクトリ内のアイテムのパスの解決

ディレクトリ内のファイルやフォルダを操作する場合は、対象のアイテムのパスを解決しておくと便利です。これは、適切な名前の resolve() メソッドで行うことができます。解決の場合、アイテムはディレクトリの直接の子または間接の子になります。

// Resolve the path of the previously created file called "My Notes.txt".
const path = await newDirectoryHandle.resolve(newFileHandle);
// `path` is now ["My Documents", "My Notes.txt"]

ディレクトリ内のファイルとフォルダを削除する

ディレクトリへのアクセス権を取得したら、removeEntry() メソッドを使用して、そのディレクトリに含まれるファイルとフォルダを削除できます。フォルダの場合は、必要に応じて再帰的に削除し、すべてのサブフォルダとその中のファイルを含めることができます。

// Delete a file.
await directoryHandle.removeEntry('Abandoned Projects.txt');
// Recursively delete a folder.
await directoryHandle.removeEntry('Old Stuff', { recursive: true });

ファイルやフォルダを直接削除する

ファイルハンドルまたはディレクトリ ハンドルにアクセスできる場合は、FileSystemFileHandle または FileSystemDirectoryHandleremove() を呼び出して削除します。

// Delete a file.
await fileHandle.remove();
// Delete a directory.
await directoryHandle.remove();

ファイルやフォルダの名前変更と移動

ファイルとフォルダの名前を変更したり、新しい場所に移動したりするには、FileSystemHandle インターフェースで move() を呼び出します。FileSystemHandle には、子インターフェース FileSystemFileHandleFileSystemDirectoryHandle があります。move() メソッドは 1 つまたは 2 つのパラメータを取ります。1 つ目は、新しい名前を含む文字列か、宛先フォルダへの FileSystemDirectoryHandle のいずれかです。後者の場合、省略可能な 2 番目のパラメータは新しい名前の文字列であるため、移動と名前変更を 1 ステップで行うことができます。

// Rename the file.
await file.move('new_name');
// Move the file to a new directory.
await file.move(directory);
// Move the file to a new directory and rename it.
await file.move(directory, 'newer_name');

ドラッグ&ドロップによる統合

HTML ドラッグ&ドロップ インターフェースを使用すると、ウェブ アプリケーションでウェブページにドラッグ&ドロップされたファイルを受け入れることができます。ドラッグ&ドロップ オペレーション中、ドラッグされたファイルとディレクトリ アイテムは、それぞれファイル エントリとディレクトリ エントリに関連付けられます。DataTransferItem.getAsFileSystemHandle() メソッドは、ドラッグされたアイテムがファイルの場合は FileSystemFileHandle オブジェクトを含む Promise を返し、ドラッグされたアイテムがディレクトリの場合は FileSystemDirectoryHandle オブジェクトを含む Promise を返します。次のリストで、実際の例を示します。ドラッグ&ドロップ インターフェースの DataTransferItem.kind は、ファイルとディレクトリの両方で "file" ですが、File System Access API の FileSystemHandle.kind は、ファイルの場合は "file"、ディレクトリの場合は "directory" です。

elem.addEventListener('dragover', (e) => {
  // Prevent navigation.
  e.preventDefault();
});

elem.addEventListener('drop', async (e) => {
  e.preventDefault();

  const fileHandlesPromises = [...e.dataTransfer.items]
    .filter((item) => item.kind === 'file')
    .map((item) => item.getAsFileSystemHandle());

  for await (const handle of fileHandlesPromises) {
    if (handle.kind === 'directory') {
      console.log(`Directory: ${handle.name}`);
    } else {
      console.log(`File: ${handle.name}`);
    }
  }
});

送信元のプライベート ファイル システムへのアクセス

オリジンのプライベート ファイル システムは、名前が示すように、ページのオリジンに限定されたストレージ エンドポイントです。通常、ブラウザは、このオリジンのプライベート ファイル システムの内容をどこかのディスクに保持することでこれを実装しますが、ユーザーがその内容にアクセスできるようにすることは意図されていません。同様に、元の非公開ファイル システムの子の名前と一致する名前のファイルまたはディレクトリが存在することは想定されません。ブラウザはファイルがあるように見えますが、これはオリジンの非公開ファイル システムであるため、ブラウザはこれらの「ファイル」をデータベースまたはその他のデータ構造に保存することがあります。基本的に、この API を使用する場合、作成されたファイルがハードディスク上のどこかで 1 対 1 で一致することはありません。ルート FileSystemDirectoryHandle にアクセスできれば、元の非公開ファイル システムで通常どおり操作できます。

const root = await navigator.storage.getDirectory();
// Create a new file handle.
const fileHandle = await root.getFileHandle('Untitled.txt', { create: true });
// Create a new directory handle.
const dirHandle = await root.getDirectoryHandle('New Folder', { create: true });
// Recursively remove a directory.
await root.removeEntry('Old Stuff', { recursive: true });

対応ブラウザ

  • Chrome: 86。
  • Edge: 86.
  • Firefox: 111。
  • Safari: 15.2。

ソース

パフォーマンスを最適化したファイルを送信元の限定公開ファイル システムからアクセスする

オリジンの非公開ファイル システムでは、ファイルのコンテンツへのインプレース書き込みアクセスや排他的書き込みアクセスなど、パフォーマンスを重視して高度に最適化された特別な種類のファイルへのアクセスをオプションで提供できます。Chromium 102 以降では、ファイル アクセスを簡素化するためのメソッドがオリジンの非公開ファイル システムに追加されています。createSyncAccessHandle()(同期読み取り / 書き込みオペレーション用)。これは FileSystemFileHandle で公開されていますが、Web Worker でのみ使用できます。

// (Read and write operations are synchronous,
// but obtaining the handle is asynchronous.)
// Synchronous access exclusively in Worker contexts.
const accessHandle = await fileHandle.createSyncAccessHandle();
const writtenBytes = accessHandle.write(buffer);
const readBytes = accessHandle.read(buffer, { at: 1 });

ポリフィル

File System Access API のメソッドを完全にポリフィルすることはできません。

  • showOpenFilePicker() メソッドは <input type="file"> 要素で近似できます。
  • showSaveFilePicker() メソッドは <a download="file_name"> 要素でシミュレートできます。ただし、このメソッドによりプログラムによるダウンロードがトリガーされ、既存のファイルを上書きすることはできません。
  • showDirectoryPicker() メソッドは、標準以外の <input type="file" webkitdirectory> 要素でエミュレートできます。

Google が開発した browser-fs-access というライブラリでは、可能な限り File System Access API を使用し、それ以外の場合は次のベスト オプションにフォールバックします。

セキュリティと権限

Chrome チームは、強力なウェブ プラットフォーム機能へのアクセスを制御するで定義されているコア プリンシプル(ユーザーによる制御と透明性、ユーザーの使いやすさなど)を使用して、File System Access API を設計して実装しました。

ファイルを開く、新しいファイルを保存する

ファイルを開いて読み取るためのファイル選択ツール
既存のファイルを開いて読み取るために使用されるファイル選択ツール。

ファイルを開くときに、ユーザーはファイル選択ツールを使用してファイルまたはディレクトリを読み取る権限を付与します。開くファイル選択ツールは、安全なコンテキストから提供される場合にのみ、ユーザー操作で表示できます。ユーザーが気が変わった場合は、ファイル選択ツールで選択をキャンセルできます。その場合、サイトは何もアクセスできなくなります。これは、<input type="file"> 要素の動作と同じです。

ファイルをディスクに保存するためのファイル選択ツール。
ファイルをディスクに保存するために使用するファイル選択ツール。

同様に、ウェブアプリが新しいファイルを保存しようとすると、ブラウザにファイル保存選択ツールが表示され、ユーザーは新しいファイルの名前と場所を指定できます。新しいファイルをデバイスに保存するため(既存のファイルを上書きしないため)、ファイル選択ツールはアプリにファイルへの書き込み権限を付与します。

制限付きフォルダ

ユーザーとそのデータを保護するため、ブラウザでは、Windows のコア オペレーティング システム フォルダや macOS のライブラリ フォルダなど、特定のフォルダへの保存を制限する場合があります。その場合、ブラウザにはプロンプトが表示され、ユーザーに別のフォルダを選択するように求められます。

既存のファイルまたはディレクトリの変更

ウェブアプリは、ユーザーから明示的な権限を取得せずにディスク上のファイルを変更することはできません。

権限プロンプト

以前に読み取りアクセス権を付与したファイルに変更を保存する場合、ブラウザに権限プロンプトが表示され、サイトがディスクに変更を書き込む権限を求められます。権限リクエストは、保存ボタンのクリックなど、ユーザーの操作によってのみトリガーできます。

ファイルを保存する前に表示される権限プロンプト。
既存のファイルに対する書き込み権限がブラウザに付与される前にユーザーに表示されるプロンプト。

また、IDE など、複数のファイルを編集するウェブアプリは、開くときに変更を保存する権限をリクエストすることもできます。

ユーザーが [キャンセル] を選択し、書き込みアクセス権を付与しなかった場合、ウェブアプリはローカル ファイルへの変更を保存できません。ユーザーがデータを保存するための代替方法を提供する必要があります。たとえば、ファイルを「ダウンロード」する方法や、クラウドにデータを保存する方法を提供します。

透明性

アドレスバーのアイコン
ユーザーがウェブサイトにローカル ファイルへの保存を許可したことを示すアドレスバーのアイコン。

ユーザーがウェブアプリにローカル ファイルを保存する権限を付与すると、ブラウザのアドレスバーにアイコンが表示されます。アイコンをクリックすると、ユーザーがアクセス権を付与したファイルのリストが表示されるポップオーバーが開きます。ユーザーはいつでもそのアクセス権を取り消すことができます。

権限の保持

ウェブアプリは、オリジンのタブがすべて閉じられるまで、プロンプトを表示せずにファイルへの変更を保存し続けることができます。タブを閉じると、サイトへのアクセス権がすべて失われます。ユーザーが次回ウェブアプリを使用すると、ファイルへのアクセスを求めるメッセージが再度表示されます。

フィードバック

File System Access API の使用感について、ぜひお聞かせください。

API 設計について

API が想定どおりに動作しない点はありますか?または、アイデアを実装するために必要なメソッドやプロパティが不足している場合はどうすればよいですか?セキュリティ モデルに関する質問やコメントがある場合

実装に関する問題

Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?

  • https://new.crbug.com でバグを報告します。できるだけ詳細な情報と再現手順を含めてください。[コンポーネント] を Blink>Storage>FileSystem に設定します。Glitch は、簡単な再現手順を共有するのに適しています。

API を使用する予定ですか?

サイトで File System Access API を使用する予定ですか?皆様の公開サポートは、Google が機能に優先順位を付けるのに役立ち、他のブラウザ ベンダーにそのサポートの重要性を伝えます。

関連情報

謝辞

File System Access API の仕様は Marijn Kruisselbrink によって作成されました。