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

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 の強力さと有用性を示するために、単一ファイルのテキスト エディタを作成しました。テキスト ファイルを開いて編集し、変更をディスクに保存できます。また、新しいファイルを作成して変更をディスクに保存することもできます。特別なものではありませんが、コンセプトの理解に役立ちます。

ブラウザ サポート

対応ブラウザ

  • 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'],
    },
  }],
});

デフォルトの開始ディレクトリについても同様です。テキスト エディタを作成する場合は、デフォルトの 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 は、可能な限り File System Access API を使用し、他のすべてのケースで次善のオプションにフォールバックする browser-fs-access というライブラリを開発しました。

セキュリティと権限

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 によって作成されました。