ファイルシステム

現行標準 — 最終更新

参加方法:
GitHub whatwg/fs (新規issue, オープンissue)
Matrixでチャット
コミット:
GitHub whatwg/fs/commits
このコミット時点でのスナップショット
@whatfilesystem
テスト:
web-platform-tests fs/ (進行中の作業)
翻訳 (非規範的):
日本語
简体中文
한국어

概要

ファイルシステムは、ファイルシステムのインフラとそのAPIを定義します。

1. 序章

このセクションは規範的ではありません。

この文書はファイルシステムAPIのための基盤的なインフラを定義します。また、事前にユーザーにアクセスを求めるプロンプトを表示することなく、ウェブサイトがファイルシステムディレクトリにアクセスできるAPIも定義します。これにより、ユーザーが保存先を選択する前にウェブサイトがデータをディスクに保存したい場合に、完全に異なるストレージメカニズムやAPIを使用する必要がなくなります。このエントリーポイントはnavigator.storage.getDirectory() メソッドです。

2. ファイルとディレクトリ

2.1. 概念

ファイルシステムエントリは、ファイルエントリまたはディレクトリエントリのいずれかです。

ファイルシステムエントリには、関連付けられたクエリアクセスアルゴリズムがあり、これは"read"または"readwrite" modeを取り、ファイルシステムアクセス結果を返します。 特に明記されていない場合、このアルゴリズムはファイルシステムアクセス結果を返し、その許可状態は"denied"であり、エラー名は空の文字列です。

ファイルシステムエントリには、関連付けられたリクエストアクセスアルゴリズムがあり、これは"read"または"readwrite" modeを取り、ファイルシステムアクセス結果を返します。 特に明記されていない場合、このアルゴリズムはファイルシステムアクセス結果を返し、その許可状態は"denied"であり、エラー名は空の文字列です。

ファイルシステムアクセス結果は、構造体であり、クエリアクセスまたはリクエストアクセスに基づいてファイルシステムへのアクセス結果をカプセル化します。 以下の項目を持ちます。

許可状態

PermissionState

エラー名

文字列であり、 許可状態が "granted"の場合は空文字列でなければなりません。それ以外の場合は、 名前であり、 DOMException名テーブルにリストされています。 通常、許可状態が "granted"でない場合、この値は "NotAllowedError"であるべきです。

従属する仕様では、このAPIを強力な機能と見なす場合があります。ただし、他の強力な機能のように許可リクエストアルゴリズムが例外をスローする可能性がある場合とは異なり、ファイルシステムエントリクエリアクセスリクエストアクセスアルゴリズムは並列で ファイルシステムキュー上で実行されなければならず、例外をスローすることは許されません。代わりに、呼び出し側はこれらのアルゴリズムが空文字列以外のエラー名を返した場合に適切にストレージタスクをキューにいれることで拒否することが期待されます。

注: この仕様のみを実装し、従属する仕様を実装していない場合、ファイルシステムエントリクエリアクセスリクエストアクセスを実装する必要はありません。

FileSystemHandleに関連付けられたアクセスチェックアルゴリズムを作成する必要があります。[Issue #101]

ファイルシステムエントリには関連付けられた名前 (a 文字列)があります。

有効なファイル名は、文字列であり、空文字列ではなく、"."または".."に等しくなく、'/'や基盤となるプラットフォームでパス区切り文字として使用されるその他の文字を含まないものです。

注: これは、Windowsでは名前に'\'を含めることができませんが、他のオペレーティングシステムでは許可される可能性があることを意味します。さらに、基盤となるファイルシステムには、許可される名前に関してさらなる制限がある可能性があるため、文字列が単に有効なファイル名であることは、その名前でファイルやディレクトリを作成することが成功する保証ではありません。

このAPIを使用して決して許可されないファイル名に関して、基盤となるファイルシステムに完全に任せるのではなく、さらに規範的な制限を設けることを検討する必要があります。

ファイルエントリはさらに以下を構成要素として持っています: バイナリデータ (バイトシーケンス)、変更タイムスタンプ (UNIXエポックからのミリ秒数を表す数値)、ロック (opentaken-exclusivetaken-sharedのいずれかである可能性がある文字列)、および共有ロック数 (ある時点で取られている共有ロックの数を表す数値)。

ユーザーエージェントには関連付けられたファイルシステムキューがあり、これがすべてのファイルシステム操作に使用される新しい並列キューを開始するの結果です。

ロックを取るためのアルゴリズムは、次の手順で実行されます:
  1. lockfileに関連付けられたロックとします。

  2. countfileに関連付けられた共有ロック数とします。

  3. もしvalueが"exclusive"の場合:

    1. もしlockが"open"の場合:

      1. ロックを"taken-exclusive"に設定します。

      2. "success"を返します。

  4. もしvalueが"shared"の場合:

    1. もしlockが"open"の場合:

      1. lockを"taken-shared"に設定します。

      2. countを1に設定します。

      3. "success"を返します。

    2. それ以外でlockが"taken-shared"の場合:

      1. countを1増やします。

      2. "success"を返します。

  5. "failure"を返します。

注: これらの手順はファイルシステムキュー上で実行される必要があります。

ロックを解放するためのアルゴリズムは、次の手順で実行されます:
  1. lockfileに関連付けられたロックとします。

  2. countfileに関連付けられた共有ロック数とします。

  3. もしlockが"taken-shared"の場合:

    1. countを1減らします。

    2. もしcountが0の場合、lockを"open"に設定します。

  4. それ以外の場合、lockを"open"に設定します。

注: これらの手順はファイルシステムキュー上で実行される必要があります。

注: ロックはファイルへの同時変更を防ぐのに役立ちます。FileSystemWritableFileStream は共有ロックを必要とし、FileSystemSyncAccessHandle は排他的なロックを必要とします。

ディレクトリエントリはさらに、集合としての 子要素を含み、これらもファイルシステムエントリです。 各要素はファイルエントリまたはディレクトリエントリのいずれかです。

ファイルシステムエントリ entryは、最大で1つの子要素として含まれるべきであり、そのディレクトリエントリはentryとしても知られています。 ファイルシステムエントリは、そのようなディレクトリエントリが存在しない場合はnullです。

注: 異なるファイルシステムエントリが、ディスク上で同じファイルまたはディレクトリを表す場合があり、 その場合、両方のエントリが異なる親を持つか、または一方が親を持ち、もう一方が親を持たない場合があります。

ファイルシステムエントリは(必須ではありませんが)ホストオペレーティングシステムのローカルファイルシステム上のファイルに裏付けされることがあり、 そのため、バイナリデータ変更タイムスタンプ、 および子要素がこの仕様外のアプリケーションによって変更される可能性があります。 外部の変更がこの仕様で定義されたデータ構造にどのように反映されるか、 またこの仕様で定義されたデータ構造に加えられた変更が外部にどのように反映されるかは、個々のユーザーエージェントの実装に委ねられています。

ファイルシステムエントリ aは、ファイルシステムエントリ b同じエントリであるとみなされます。 abと等しい場合、またはabがローカルファイルシステム上で同じファイルまたはディレクトリに裏付けされている場合です。

ファイルシステムロケータ childを、ディレクトリロケータ rootに相対的に解決するには以下の手順を実行します:

  1. result新しいプロミスとします。

  2. 以下の手順をエンキューして、ファイルシステムキューに追加します:

    1. もしchildロケータルートrootロケータルートと異なる場合、 nullで解決し、これらの手順を中止します。

    2. childPathchildロケータパスとします。

    3. rootPathrootロケータパスとします。

    4. もしchildPath同じパスとしてrootPathと一致する場合、 « »で解決し、これらの手順を中止します。

    5. もしrootPathサイズchildPathサイズより大きい場合、 nullで解決し、これらの手順を中止します。

    6. indexについてrootPathインデックスを反復します:

      1. もしrootPath.[[index]]が childPath.[[index]]と一致しない場合、 nullで解決し、これらの手順を中止します。

    7. relativePathを« »とします。

    8. indexについて範囲rootPathサイズ からrootPathサイズまで(排他的)を反復し、 追加します。 childPath.[[index]]をrelativePathに追加します。

    9. 解決relativePathで行います。

  3. resultを返します。

ファイルシステムロケータ は、ファイルシステムエントリの潜在的な場所を表します。ファイルシステムロケータは、ファイルロケータ またはディレクトリロケータのいずれかです。

ファイルシステムロケータには、関連付けられたパス (ファイルシステムパス)、 種類 (FileSystemHandleKind)、 およびルート (ファイルシステムルート)があります。

各ロケータにストレージバケットを与えることを検討してください。 [Issue #109]

ファイルロケータは、ファイルシステムロケータであり、 その種類が"file"です。 ディレクトリロケータは、ファイルシステムロケータであり、 その種類が"directory"です。

ファイルシステムルートは、 不透明な文字列であり、 その値は実装依存です。

ファイルシステムロケータ locatorが、 位置付ける ファイルエントリ entryが、 バケットファイルシステムのルートディレクトリに対して data/drafts/example.txtというパスに概念的に存在する場合、 locator種類は"file"でなければならず、 locatorパスは« "data", "drafts", "example.txt" »でなければならず、 locatorルートには、 ストレージバケットやディスクドライブのような関連する識別情報を含む場合があります。

ファイルシステムロケータ aは、 ファイルシステムロケータ b同じロケータであるとみなされます。 それはa種類b種類と同じであり、 aルートbルートと同じであり、 aパス同じパスとしてbパスと一致する場合です。

エントリを特定するアルゴリズムは、 ファイルシステムロケータ locatorを受け取り、 以下の実装依存の手順を実行します:
ロケータを取得するアルゴリズムは、 ファイルシステムエントリ entryを受け取り、 以下の実装依存の手順を実行します:

ファイルシステムパスは、 1つ以上の項目で構成される、 文字列のリストです。 これは、ディスクまたはメモリ上の実際の場所にマッピングされた仮想パスである場合や、 ローカルファイルシステム上のパスに直接対応する場合、 またはディスク上のいかなるファイルにも対応しない場合があります。 対応するファイルシステムエントリの実際の物理的位置は、 実装依存です。

pathリスト « "data", "drafts", "example.txt" »とします。 ディスク上にexample.txtという名前のファイルが存在するという期待はありません。

ファイルシステムパス aは、ファイルシステムパス b同じパスであるとみなされます。 それは、aサイズbサイズと同じであり、 indexについて、 aインデックスa.[[index]]とb.[[index]]が一致する場合です。

ファイルシステムロケータ の内容、特にその パス は、ウェブサイトプロセスに完全に共有されることは想定されていません。 ファイルシステムパス には、ファイルシステムロケータ が後に親 ディレクトリロケータ を基点として 解決 されない限り、ウェブサイトに知られていない可能性のあるコンポーネントが含まれている場合があります。

2.2. FileSystemHandle インターフェイス

enum FileSystemHandleKind {
  "file",
  "directory",
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemHandle {
  readonly attribute FileSystemHandleKind kind;
  readonly attribute USVString name;

  Promise<boolean> isSameEntry(FileSystemHandle other);
};

FileSystemHandle オブジェクトはロケータファイルシステムロケータ) に関連付けられています。

注: 複数のFileSystemHandle オブジェクトは同じロケータを持つことがあります。

FileSystemHandle バケットファイルシステム内にある のは、その ロケータパス の最初の 項目 が空文字列である場合です。

注: これは少し特殊ですが、バケットファイルシステムのルートディレクトリのみが 空文字列を含むパスを持つことができるため、機能します。 その他の項目はすべて有効なファイル名である必要があります。 詳細はgetDirectory() を参照してください。

各ロケータにストレージバケットを付与することで、この状況を改善することを検討してください。[Issue #109]

FileSystemHandle オブジェクトはシリアライズ可能なオブジェクトです。

以下は、valueserialized、およびforStorageを与えられたときのシリアライズ手順です。

  1. serialized.[[Origin]]をvalue関連する設定オブジェクトオリジンに設定します。

  2. serialized.[[Locator]]をvalueロケータに設定します。

以下は、serializedおよびvalueを与えられたときのデシリアライズ手順です。
  1. もしserialized.[[Origin]]がvalue関連する設定オブジェクトオリジン同一オリジンでない場合、 "DataCloneError" DOMExceptionスローします。

  2. valueロケータserialized.[[Locator]]に設定します。

handle . kind

もしhandleFileSystemFileHandle であれば、"file"を返し、 もしhandleFileSystemDirectoryHandle であれば、"directory"を返します。

これは、ディレクトリの内容を反復処理する際にファイルとディレクトリを区別するために使用できます。

handle . name

handleロケータパスの最後のパスコンポーネントを返します。

kindのゲッター手順は、 thisロケータ種類を返します。

nameのゲッター手順は、 thisロケータパスの最後の項目文字列)を返します。

2.2.1. The isSameEntry() メソッド

same = await handle1 . isSameEntry( handle2 )

もし handle1handle2 が同じファイルまたはディレクトリを表す場合、true を返します。

isSameEntry(other)メソッドの手順は以下の通りです:
  1. realmthis関連する Realm とする。

  2. p新しい Promise として realm 内で生成する。

  3. 以下の手順を ファイルシステムキュー にエンキューする:

    1. もし thislocator同じ locatorotherlocator として持つ場合、 resolve p を true で解決する。

    2. それ以外の場合、resolve p を false で解決する。

  4. p を返す。

2.3. FileSystemFileHandle インターフェース

dictionary FileSystemCreateWritableOptions {
  boolean keepExistingData = false;
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemFileHandle : FileSystemHandle {
  Promise<File> getFile();
  Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
  [Exposed=DedicatedWorker]
  Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
};

Note: FileSystemFileHandle の関連する locatorkind は "file" です。

directory locator parentLocator と文字列 name を与えられた場合に 子の FileSystemFileHandle を作成する 手順は次の通りです:
  1. handle新しい FileSystemFileHandle として realm 内で生成する。

  2. childType を "file" とする。

  3. childRootparentLocatorroot のコピーとする。

  4. childPathclone した parentLocatorpathappend した name とする。

  5. handlelocator を以下の ファイルシステムロケータ として設定する:その kindchildTyperootchildRoot、そして pathchildPath

  6. handle を返す。

FileSystemFileHandle オブジェクトはシリアライズ可能なオブジェクトです。それらのシリアライズ手順および デシリアライズ手順FileSystemHandle と同じです。

2.3.1. getFile() メソッド

file = await fileHandle . getFile()

File を返し、handlelocator によって 見つけることができる ファイルエントリ のディスク上の状態を表します。 このメソッド呼び出し後にディスク上のファイルが変更または削除された場合、返された File オブジェクトはおそらく読み取れなくなる可能性があります。

getFile()メソッドの手順は以下の通りです:
  1. result新しい Promise として作成する。

  2. locatorthislocator とする。

  3. globalthis関連するグローバルオブジェクト とする。

  4. 以下の手順をエンキューする ファイルシステムキュー に:

    1. entry を、エントリを見つける手順を locator に対して実行した結果とする。

    2. accessResult を、entryquery access に "read" を渡して実行した結果とする。

    3. ストレージタスクをキューに追加する global を使用して以下を実行:

      1. もし accessResultpermission state が "granted" でない場合、 reject resultaccessResultエラー名 を持つ DOMException として解決し、これらの手順を中止する。

      2. もし entry が null の場合、reject result を "NotFoundError" DOMException として解決し、これらの手順を中止する。

      3. アサート: entryファイルエントリ であること。

      4. f を新しい File とする。

      5. fスナップショット状態entry の現在の状態に設定する。

      6. f の基礎となるバイトシーケンスを entryバイナリデータ のコピーに設定する。

      7. fnameentryname に設定する。

      8. flastModifiedentry修正タイムスタンプ に設定する。

      9. ftype を例えば entryname やそのファイル拡張子に基づく 実装依存の値 に設定する。

        読み取りおよびスナップショットの動作仕様については、[FILE-API] 仕様にてさらに詳細に記述する必要がありますが、 現在のところは曖昧なままです。

      10. resolve resultf で解決する。

  5. result を返す。

2.3.2. createWritable() メソッド

stream = await fileHandle . createWritable()
stream = await fileHandle . createWritable({ keepExistingData: true/false })

FileSystemWritableFileStream を返し、ファイルに書き込みを行うために使用できます。stream を通じて行われた変更は、 fileHandlelocator により 見つけることのできる ファイルエントリ に、stream が 閉じられるまで反映されません。ユーザーエージェントは部分的な書き込みが発生しないようにします。 つまり、ファイルは古い内容を保持するか、stream を通じて書き込まれたすべてのデータを含むかのいずれかになります。

これは通常、一時ファイルにデータを書き込むことで実装され、書き込みストリームが閉じられたときに、 fileHandlelocator により 見つけることのできる ファイルエントリ を一時ファイルで置き換えることで行われます。

もし keepExistingData が false または指定されていない場合、一時ファイルは空の状態で開始されます。 それ以外の場合、既存のファイルは最初にこの一時ファイルにコピーされます。

FileSystemWritableFileStream を作成することは、fileHandlelocator により 見つけることのできる ファイルエントリ に対して 共有ロック を取得します。 これにより、ストリームが閉じられるまで、エントリに対する FileSystemSyncAccessHandles の作成が防止されます。

createWritable の「inPlace」モード(例えば、大きなファイルやデータベースのようなものの インプレースな変更をサポートするために、書き込みが行われるたびに基礎となる実際のファイルに変更を書き込む)に関する議論や要望については、 WICG/file-system-access issue #67 を参照してください。 これは現在 Chrome では実装されていません。 これを実装するには、マルウェアチェックを実行したいという要望と、 既存の大きなファイルに対して迅速なインプレース変更を行いたいという要望をどのように組み合わせるかを 解決する必要があります。インプレース書き込みは バケットファイルシステム 内のファイルに対して、 FileSystemSyncAccessHandle インターフェースを介して利用可能です。

createWritable(options) メソッドの手順は以下の通りです:
  1. result新しい Promise として作成する。

  2. locatorthislocator とする。

  3. realmthis関連する Realm とする。

  4. globalthis関連するグローバルオブジェクト とする。

  5. 以下の手順をエンキューする ファイルシステムキュー に:

    1. entry を、エントリを見つける手順を locator に対して実行した結果とする。

    2. accessResult を、entryrequest access に "readwrite" を渡して実行した結果とする。

    3. もし accessResultpermission state が "granted" でない場合、 ストレージタスクをキューに追加する global を使用して、 reject resultaccessResultエラー名 を持つ DOMException として解決し、これらの手順を中止する。

    4. もし entrynull の場合、 ストレージタスクをキューに追加する global を使用して、 reject result を "NotFoundError" DOMException として解決し、これらの手順を中止する。

    5. アサート: entryファイルエントリ であること。

    6. lockResult を、ロックを取得する 手順を "shared" を指定して entry に対して実行した結果とする。

    7. ストレージタスクをキューに追加する global を使用して以下を実行:

      1. もし lockResult が "failure" の場合、 reject result を "NoModificationAllowedError" DOMException として解決し、これらの手順を中止する。

      2. stream を、新しい FileSystemWritableFileStream を作成する 手順を entry に対して realm 内で実行した結果とする。

      3. もし options["keepExistingData"] が true の場合:

        1. stream[[buffer]] を、 entryバイナリデータ のコピーに設定する。

      4. resolve resultstream で解決する。

  6. result を返す。

2.3.3. createSyncAccessHandle() メソッド

handle = await fileHandle . createSyncAccessHandle()

FileSystemSyncAccessHandle を返し、ファイルの読み取り/書き込みに使用できます。 handle を通じて行われた変更は、fileHandlelocator により 見つけることができる ファイルエントリ に即座に反映される場合があります。 この変更をファイルに確実に反映するには、ハンドルをフラッシュすることができます。

FileSystemSyncAccessHandle を作成すると、 fileHandlelocator により 見つけることができる ファイルエントリ に対して 排他ロック を取得します。 これにより、アクセスハンドルが閉じられるまで、エントリに対する追加の FileSystemSyncAccessHandles または FileSystemWritableFileStreams の作成が防止されます。

返された FileSystemSyncAccessHandle は同期メソッドを提供します。これにより、非同期操作に高いオーバーヘッドが伴うコンテキスト(例えば、WebAssembly)での 高パフォーマンスが可能になります。

現在、このメソッドは fileHandleバケットファイルシステム内にある 場合にのみ成功します。

createSyncAccessHandle() メソッドの手順は以下の通りです:
  1. result新しい Promise として作成する。

  2. locatorthislocator とする。

  3. realmthis関連する Realm とする。

  4. globalthis関連するグローバルオブジェクト とする。

  5. isInABucketFileSystem を true とし、thisバケットファイルシステム内にある かどうかを判定する。それ以外の場合は false とする。

  6. 以下の手順をエンキューする ファイルシステムキュー に:

    1. entry を、エントリを見つける手順を locator に対して実行した結果とする。

    2. accessResult を、entryrequest access に "readwrite" を渡して実行した結果とする。

    3. もし accessResultpermission state が "granted" でない場合、 ストレージタスクをキューに追加する global を使用して、 reject resultaccessResultエラー名 を持つ DOMException として解決し、これらの手順を中止する。

    4. もし isInABucketFileSystem が false の場合、 ストレージタスクをキューに追加する global を使用して、 reject result を "InvalidStateError" DOMException として解決し、これらの手順を中止する。

    5. もし entrynull の場合、 ストレージタスクをキューに追加する global を使用して、 reject result を "NotFoundError" DOMException として解決し、これらの手順を中止する。

    6. アサート: entryファイルエントリ であること。

    7. lockResult を、ロックを取得する 手順を "exclusive" を指定して entry に対して実行した結果とする。

    8. ストレージタスクをキューに追加する global を使用して以下を実行:

      1. もし lockResult が "failure" の場合、 reject result を "NoModificationAllowedError" DOMException として解決し、これらの手順を中止する。

      2. handle を、新しい FileSystemSyncAccessHandle を作成する 手順を entry に対して realm 内で実行した結果とする。

      3. resolve resulthandle で解決する。

  7. result を返す。

2.4. FileSystemDirectoryHandle インターフェース

dictionary FileSystemGetFileOptions {
  boolean create = false;
};

dictionary FileSystemGetDirectoryOptions {
  boolean create = false;
};

dictionary FileSystemRemoveOptions {
  boolean recursive = false;
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemDirectoryHandle : FileSystemHandle {
  async_iterable<USVString, FileSystemHandle>;

  Promise<FileSystemFileHandle> getFileHandle(USVString name, optional FileSystemGetFileOptions options = {});
  Promise<FileSystemDirectoryHandle> getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});

  Promise<undefined> removeEntry(USVString name, optional FileSystemRemoveOptions options = {});

  Promise<sequence<USVString>?> resolve(FileSystemHandle possibleDescendant);
};

注意: FileSystemDirectoryHandle の関連する locatorkind は "directory" です。

directory locator parentLocator と文字列 name を与えられた場合に 子の FileSystemDirectoryHandle を作成する 手順は次の通りです:
  1. handle新しい FileSystemDirectoryHandle として realm 内で生成する。

  2. childType を "directory" とする。

  3. childRootparentLocatorroot のコピーとする。

  4. childPathclone した parentLocatorpathappend した name とする。

  5. handlelocator を以下の ファイルシステムロケータ として設定する:その kindchildTyperootchildRoot、そして pathchildPath

  6. handle を返す。

file system root rootfile system path path を与えられた場合に 新しい FileSystemDirectoryHandle を作成する 手順は次の通りです:
  1. handle新しい FileSystemDirectoryHandle として realm 内で生成する。

  2. handlelocator を以下の ファイルシステムロケータ として設定する:その kind は "directory"、 rootroot、そして pathpath

  3. handle を返す。

FileSystemDirectoryHandle オブジェクトはシリアライズ可能なオブジェクトです。それらのシリアライズ手順および デシリアライズ手順FileSystemHandle と同じです。

2.4.1. ディレクトリの反復処理

for await (let [name, handle] of directoryHandle) {}
for await (let [name, handle] of directoryHandle . entries()) {}
for await (let handle of directoryHandle . values()) {}
for await (let name of directoryHandle . keys()) {}

directoryHandlelocator により 見つけることができる ディレクトリエントリ を親とするすべてのエントリを反復処理します。 反復処理中に作成または削除されたエントリが含まれるかどうかは保証されません。

将来的には、再帰的反復処理などをサポートするために async_iterable 宣言に引数を追加することを検討するかもしれません。[Issue #15]

非同期イテレータ初期化手順 に基づいて FileSystemDirectoryHandle handle とその非同期イテレータ iterator を初期化する手順は次の通りです:
  1. iterator過去の結果 を空の セット に設定する。

次の反復結果を取得するための FileSystemDirectoryHandle handle とその非同期イテレータ iterator の手順は次の通りです:
  1. promise新しい Promise として作成する。

  2. 以下の手順をエンキューする ファイルシステムキュー に:

    1. directory を、エントリを見つける 手順を handlelocator に対して実行した結果とする。

    2. accessResult を、directoryquery access に "read" を渡して実行した結果とする。

    3. ストレージタスクをキューに追加する handle関連するグローバルオブジェクト を使用して以下を実行:

      1. もし accessResultpermission state が "granted" でない場合、 reject promiseaccessResultエラー名 を持つ DOMException として解決し、これらの手順を中止する。

      2. もし directorynull の場合、 reject promise を "NotFoundError" DOMException として解決し、これらの手順を中止する。

        1. アサート: directoryディレクトリエントリ であること。

      3. childdirectory の中から、childnameiterator過去の結果 に 含まれていないものとして選び、それが存在しない場合は null とする。

        注意: これは意図的に反復順序について非常に曖昧にしています。 異なるプラットフォームやファイルシステムは反復順序について異なる保証を提供し、すべてのプラットフォームで効率的に実装できるようにしたいと考えています。 したがって、どの順序で要素が返されるかについては一切保証されません。

      4. もし childnull の場合、 resolve promiseundefined として解決し、これらの手順を中止する。

      5. 追加 childnameiterator過去の結果 に。

      6. もし childファイルエントリ である場合:

        1. result子の FileSystemFileHandle を作成する 手順を handlelocatorchildname に対して handle関連する Realm 内で実行した結果とする。

      7. それ以外の場合:

        1. result子の FileSystemDirectoryHandle を作成する 手順を handlelocatorchildname に対して handle関連する Realm 内で実行した結果とする。

      8. resolve promise を (childname, result) で解決する。

  3. promise を返す。

2.4.2. The getFileHandle() メソッド

fileHandle = await directoryHandle . getFileHandle(name)
fileHandle = await directoryHandle . getFileHandle(name, { create: false })

directoryHandleディレクトリエントリ によって 位置特定可能name という名前のファイルのハンドルを返します。 存在しない場合、この操作は拒否されます。

fileHandle = await directoryHandle . getFileHandle(name, { create: true })

directoryHandleディレクトリエントリ によって 位置特定可能name という名前のファイルのハンドルを返します。 存在しない場合、この操作は新しいファイルを作成します。 name という名前のファイルを作成できない場合、この操作は拒否されます。 作成は、同じ名前を持つディレクトリが既に存在する、基盤となるファイルシステムでサポートされていない文字を名前に使用している、またはユーザーエージェントがセキュリティ上の理由でファイルの作成を許可しなかったために失敗することがあります。

この操作には書き込み権限が必要です。返されるファイルが既に存在する場合でも同様です。 このハンドルが既に書き込み権限を持っていない場合、ユーザーにプロンプトを表示する可能性があります。 書き込み権限を必要とせずに既存のファイルを取得するには、このメソッドを { create: false } と共に呼び出してください。

getFileHandle(name, options) メソッドの手順は以下の通りです:
  1. result新しいプロミス とします。

  2. realmthis関連する Realm とします。

  3. locatorthisロケーター とします。

  4. globalthis関連するグローバルオブジェクト とします。

  5. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

    1. もし name有効なファイル名 でない場合、ストレージタスクをエンキュー して globalプロミスを拒否 し、TypeError を 用いてこれらの手順を中止します。

    2. entryエントリを位置特定 する結果とします。

    3. もし options["create"] が true の場合:

      1. accessResultentryアクセス要求 を "readwrite" にして実行した結果とします。

    4. それ以外の場合:

      1. accessResultentryアクセスクエリ を "read" にして実行した結果とします。

    5. ストレージタスクをエンキュー して、global に以下の手順を実行させます:

      1. もし accessResult権限状態 が "granted" でない 場合、プロミスを拒否 して accessResultエラー名 を用いてこれらの手順を中止します。

      2. もし entrynull の場合、プロミスを拒否 して "NotFoundError" DOMException を 用いてこれらの手順を中止します。

      3. アサート: entryディレクトリエントリ です。

      4. entry子要素 について child を繰り返します:

        1. もし child名前name と等しい場合:

          1. もし childディレクトリエントリ の場合:

            1. プロミスを拒否 して "TypeMismatchError" DOMException を 用いてこれらの手順を中止します。

          2. プロミスを解決 して FileSystemFileHandle を作成 した結果を locatorchild名前 を用いて realm 内で返し、 これらの手順を中止します。

      5. もし options["create"] が false の場合:

        1. プロミスを拒否 して "NotFoundError" DOMException を 用いてこれらの手順を中止します。

      6. child を新しい ファイルエントリ とし、その アクセスクエリアクセス要求 アルゴリズムを entry のものとします。

      7. child名前name に設定します。

      8. childバイナリデータ を空の バイトシーケンス に設定します。

      9. child変更タイムスタンプ を 現在の時刻に設定します。

      10. 追加 として childentry子要素 に加えます。

      11. 基盤となるファイルシステムで child を作成する際に例外がスローされた場合、 プロミスを拒否 してその例外を用い、これらの手順を中止します。

        可能性のある例外をさらに具体化してください。 [Issue #11]

      12. プロミスを解決 して FileSystemFileHandle を作成 した結果を locatorchild名前 を用いて realm 内で返します。

  6. result を返します。

2.4.3. getDirectoryHandle() メソッド

subdirHandle = await directoryHandle . getDirectoryHandle(name)
subdirHandle = await directoryHandle . getDirectoryHandle(name, { create: false })

directoryHandleディレクトリエントリ によって 位置特定可能name という名前のディレクトリのハンドルを返します。 存在しない場合、この操作は拒否されます。

subdirHandle = await directoryHandle . getDirectoryHandle(name, { create: true })

directoryHandleディレクトリエントリ によって 位置特定可能name という名前のディレクトリのハンドルを返します。 存在しない場合、新しいディレクトリを作成します。 ディレクトリの作成に失敗した場合、この操作は拒否されます。 作成は、同じ名前を持つファイルが既に存在する場合、または基盤となるファイルシステムでサポートされていない文字を名前に使用している場合に失敗することがあります。

この操作には書き込み権限が必要です。返されるディレクトリが既に存在する場合でも同様です。 このハンドルが既に書き込み権限を持っていない場合、ユーザーにプロンプトを表示する可能性があります。 書き込み権限を必要とせずに既存のディレクトリを取得するには、このメソッドを { create: false } と共に呼び出してください。

getDirectoryHandle(name, options) メソッドの手順は以下の通りです:
  1. result新しいプロミス とします。

  2. realmthis関連する Realm とします。

  3. locatorthisロケーター とします。

  4. globalthis関連するグローバルオブジェクト とします。

  5. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

    1. もし name有効なファイル名 でない場合、ストレージタスクをエンキュー して globalプロミスを拒否 し、TypeError を 用いてこれらの手順を中止します。

    2. entryエントリを位置特定 する結果とします。

    3. もし options["create"] が true の場合:

      1. accessResultentryアクセス要求 を "readwrite" にして実行した結果とします。

    4. それ以外の場合:

      1. accessResultentryアクセスクエリ を "read" にして実行した結果とします。

    5. ストレージタスクをエンキュー して、global に以下の手順を実行させます:

      1. もし accessResult権限状態 が "granted" でない 場合、プロミスを拒否 して accessResultエラー名 を用いてこれらの手順を中止します。

      2. もし entrynull の場合、プロミスを拒否 して "NotFoundError" DOMException を 用いてこれらの手順を中止します。

      3. アサート: entryディレクトリエントリ です。

      4. entry子要素 について child を繰り返します:

        1. もし child名前name と等しい場合:

          1. もし childファイルエントリ の場合:

            1. プロミスを拒否 して "TypeMismatchError" DOMException を 用いてこれらの手順を中止します。

          2. プロミスを解決 して FileSystemDirectoryHandle を作成 した結果を locatorchild名前 を用いて realm 内で返し、 これらの手順を中止します。

      5. もし options["create"] が false の場合:

        1. プロミスを拒否 して "NotFoundError" DOMException を 用いてこれらの手順を中止します。

      6. child を新しい ディレクトリエントリ とし、その アクセスクエリアクセス要求 アルゴリズムを entry のものとします。

      7. child名前name に設定します。

      8. child子要素 を空の セット に設定します。

      9. 追加 として childentry子要素 に加えます。

      10. 基盤となるファイルシステムで child を作成する際に例外がスローされた場合、 プロミスを拒否 してその例外を用い、これらの手順を中止します。

        可能性のある例外をさらに具体化してください。 [Issue #11]

      11. プロミスを解決 して FileSystemDirectoryHandle を作成 した結果を locatorchild名前 を用いて realm 内で返します。

  6. result を返します。

2.4.4. removeEntry() メソッド

await directoryHandle . removeEntry(name)
await directoryHandle . removeEntry(name, { recursive: false })

directoryHandleディレクトリエントリ位置特定可能 エントリに name という名前のファイル、または空のディレクトリが含まれている場合、これを削除しようとします。

存在しないファイルやディレクトリを削除しようとする場合は成功とみなされますが、空でないディレクトリを削除しようとするとプロミスが拒否されます。

await directoryHandle . removeEntry(name, { recursive: true })

directoryHandleディレクトリエントリ位置特定可能 エントリに name という名前のファイルシステムエントリを削除します。 そのエントリがディレクトリの場合、その内容も再帰的に削除されます。

存在しないファイルやディレクトリを削除しようとする場合は成功とみなされます。

removeEntry(name, options) メソッドの手順は以下の通りです:
  1. result新しいプロミス とします。

  2. locatorthisロケーター とします。

  3. globalthis関連するグローバルオブジェクト とします。

  4. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

    1. もし name有効なファイル名 でない場合、ストレージタスクをエンキュー して globalプロミスを拒否 し、TypeError を 用いてこれらの手順を中止します。

    2. entryエントリを位置特定 する結果とします。

    3. accessResultentryアクセス要求 を "readwrite" にして実行した結果とします。

    4. ストレージタスクをエンキュー して、global に以下の手順を実行させます:

      1. もし accessResult権限状態 が "granted" でない場合、 プロミスを拒否 して accessResultエラー名 を用いてこれらの手順を中止します。

      2. もし entrynull の場合、プロミスを拒否 して "NotFoundError" DOMException を 用いてこれらの手順を中止します。

      3. アサート: entryディレクトリエントリ です。

      4. entry子要素 について child を繰り返します:

        1. もし child名前name と等しい場合:

          1. もし childディレクトリエントリ の場合:

            1. もし child子要素空でない かつ options["recursive"] が false の場合:

              1. プロミスを拒否 して "InvalidModificationError" DOMException を 用いてこれらの手順を中止します。

          2. 削除 として childentry子要素 から取り除きます。

          3. 基盤となるファイルシステムで child を削除する際に例外がスローされた場合、 プロミスを拒否 してその例外を用い、これらの手順を中止します。

            注: recursive が true の場合、削除は非原子的に失敗する可能性があります。 一部のファイルまたはディレクトリは削除されるかもしれませんが、他のファイルやディレクトリはまだ存在している可能性があります。

            可能性のある例外をさらに具体化してください。 [Issue #11]

          4. プロミスを解決 して undefined を返します。

      5. プロミスを拒否 して "NotFoundError" DOMException を返します。

  5. result を返します。

2.4.5. resolve() メソッド

path = await directory . resolve( child )

もし childdirectory と等しい場合、path は空の配列になります。

もし childdirectory の直接の子である場合、pathchild の名前を含む配列になります。

もし childdirectory の子孫である場合、path は すべての中間ディレクトリの名前と child の名前を最後の要素として含む配列になります。 たとえば、directory/home/user/project を表し、 child/home/user/project/foo/bar を表す場合、これは ['foo', 'bar'] を返します。

それ以外の場合(directorychild が関連していない場合)、path は null になります。

// 有効なディレクトリハンドルを取得したと仮定します。
const dir_ref = current_project_dir;
if (!dir_ref) return;

// 次にファイルの参照を取得します:
const file_ref = await dir_ref.getFileHandle(filename, { create: true });

// file_ref が dir_ref 内に存在するか確認します:
const relative_path = await dir_ref.resolve(file_ref);
if (relative_path === null) {
    // dir_ref 内に存在しません。
} else {
    // relative_path は名前の配列で、dir_ref から file_ref を表すファイルまでの相対パスを示します:
    assert relative_path.pop() === file_ref.name;

    let entry = dir_ref;
    for (const name of relative_path) {
        entry = await entry.getDirectory(name);
    }
    entry = await entry.getFile(file_ref.name);

    // |entry| はディスク上で |file_ref| と同じファイルを表します。
    assert await entry.isSameEntry(file_ref) === true;
}
The resolve(possibleDescendant) メソッドの手順は possibleDescendantロケーターthisロケーター に対して 解決 した結果を返すことです。

2.5. FileSystemWritableFileStream インターフェース

enum WriteCommandType {
  "write",
  "seek",
  "truncate",
};

dictionary WriteParams {
  required WriteCommandType type;
  unsigned long long? size;
  unsigned long long? position;
  (BufferSource or Blob or USVString)? data;
};

typedef (BufferSource or Blob or USVString or WriteParams) FileSystemWriteChunkType;

[Exposed=(Window,Worker), SecureContext]
interface FileSystemWritableFileStream : WritableStream {
  Promise<undefined> write(FileSystemWriteChunkType data);
  Promise<undefined> seek(unsigned long long position);
  Promise<undefined> truncate(unsigned long long size);
};

FileSystemWritableFileStream[[file]]ファイルエントリ)を関連付けられています。

FileSystemWritableFileStream[[buffer]]バイトシーケンス)を関連付けられています。 初期状態では空です。

注: このバッファは任意の大きさになり得るため、実装ではこれをメモリ上に保持するのではなく、 一時ファイルを使用することが期待されます。[[buffer]] へのすべてのアクセスはプロミスを返すメソッドとアルゴリズムで行われるため、 操作は同期的に見えますが、実装は非同期的にそれらを実行できます。

FileSystemWritableFileStream[[seekOffset]](数値)を関連付けられています。 初期値は 0 です。

FileSystemWritableFileStream オブジェクトは、WritableStream オブジェクトに追加の便利なメソッドを備えたもので、ディスク上の単一ファイルを操作します。

作成時に、基盤となるシンクが作成され、ストリームは使用可能になります。 ストリームで実行されるすべての操作はキュー可能であり、プロデューサーはバックプレッシャーに応答することができます。

基盤となるシンクの write メソッド、および WritableStreamDefaultWriter の write() メソッドでは、バイト状のデータまたは WriteParams を入力として受け付けます。

FileSystemWritableFileStream は、ファイルの先頭からバイトオフセット 0 に初期化されたファイル位置カーソルを持っています。 write() を使用するか、WritableStream の機能を通じて WritableStreamDefaultWriter の write() メソッドを使用することで、この位置はストリームオブジェクトを介して書き込まれたバイト数に基づいて進みます。

同様に、ReadableStreamFileSystemWritableFileStream オブジェクトにパイプすると、この位置はストリームを通過したバイト数で更新されます。

getWriter() は、WritableStreamDefaultWriter のインスタンスを返します。

新しい FileSystemWritableFileStream を作成する ために、ファイルエントリ fileRealm realm に与えます:
  1. stream新しい FileSystemWritableFileStream として realm 内に作成します。

  2. stream[[file]]file に設定します。

  3. writeAlgorithmchunk 引数を取り、stream および chunk を用いて チャンクを書き込む アルゴリズムを実行した結果を返すアルゴリズムとします。

  4. closeAlgorithm を次の手順とします:

    1. closeResult新しいプロミス とします。

    2. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

      1. accessResultfileアクセスクエリ を "readwrite" にして実行した結果とします。

      2. ストレージタスクをエンキュー して file関連するグローバルオブジェクト に以下の手順を実行させます:

        1. もし accessResult権限状態 が "granted" でない場合、 プロミスを拒否 して accessResultエラー名 を用いてこれらの手順を中止します。

        2. 実装依存 のマルウェアスキャンおよび安全なブラウジングチェックを実行します。 これらのチェックが失敗した場合、プロミスを拒否 して "AbortError" DOMException を 用いてこれらの手順を中止します。

        3. stream[[file]]バイナリデータstream[[buffer]] に設定します。 それが例外をスローした場合、プロミスを拒否 してその例外を用いてこれらの手順を中止します。

          注: これは書き込み対象の ディスク上のファイルの内容を原子的に更新することが期待されています。

        4. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

          1. ロックを解放 して stream[[file]] に設定します。

          2. ストレージタスクをエンキュー して file関連するグローバルオブジェクトプロミスを解決 して undefined を返します。

    3. closeResult を返します。

  5. abortAlgorithm を次の手順とします:

    1. 以下の手順をエンキュー して、ファイルシステムキュー に送ります:

      1. ロックを解放 して stream[[file]] に設定します。

  6. highWaterMark を 1 に設定します。

  7. sizeAlgorithm1 を返すアルゴリズムとします。

  8. セットアップstream に対して行い、writeAlgorithmwriteAlgorithm に、closeAlgorithmcloseAlgorithm に、abortAlgorithmabortAlgorithm に、highWaterMarkhighWaterMark に、そして sizeAlgorithmsizeAlgorithm に設定します。

  9. stream を返します。

チャンクを書き込む アルゴリズムは、 FileSystemWritableFileStream streamチャンクを受け取り、以下の手順を実行します:
  1. inputを、ECMAScript値をIDL値に変換する結果として設定します。 この操作で例外がスローされた場合、その例外で拒否されたPromiseを返します。

  2. p新しいPromiseにします。

  3. 以下の手順をエンキューしてファイルシステムキューに追加します:

    1. accessResultを取得するために、 stream[[file]]アクセスを照会し、引数に"readwrite"を渡します。

    2. ストレージタスクをキューに追加し、 stream関連するグローバルオブジェクトで以下の手順を実行します:

      1. もしaccessResult許可状態 が"granted"でない場合、 拒否されたpaccessResultエラー名を含むDOMException として返して、この手順を中止します。

      2. commandを、inputが"type"を持つ場合その値に、 それ以外の場合は"write"に設定します。

      3. もしcommandが"write"の場合:

        1. もしinputundefinedであるか、input辞書であり、 input["data"] が存在しない場合、 拒否されたpTypeError として返し、これらの手順を中止します。

        2. dataを、inputが["data"] を持つ場合その値に、それ以外の場合はinputに設定します。

        3. writePositionstream[[seekOffset]] に設定します。

        4. もしinput辞書であり、 input["position"] 存在する場合、writePositioninput["position"] に設定します。

        5. oldSizestream[[buffer]]長さに設定します。

        6. もしdataBufferSource である場合、dataBytesコピーした結果 とします。

        7. そうでない場合、もしdataBlobである場合:

          1. dataBytes読み取り操作dataに対して実行した結果とします。 これが例外をスローした場合、その例外で拒否されたpを返し、 これらの手順を中止します。

        8. それ以外の場合:

          1. 断言: dataUSVString である。

          2. dataBytesUTF-8エンコードした dataの結果とします。

        9. もしwritePositionoldSizeより大きい場合、 writePosition - oldSize分の0x00 (NUL)バイトを stream[[buffer]] の末尾に追加します。

          注: 実装はスキップされたファイル内容が実際にNULバイトで埋められているかのように動作することが期待されます。 これらのバイトが実際にディスクに書き込まれディスクスペースを占有する必要はありません。 代わりに、多くのファイルシステムはスパースファイルをサポートしており、 これらのNULバイトが実際のディスクスペースを占有しないようにすることができます。

        10. headバイト列で、 writePositionバイト分のstream[[buffer]] の先頭部分を持つものに設定します。

        11. tailを空のバイト列に設定します。

        12. もしwritePosition + data長さoldSizeより小さい場合:

          1. tailバイト列で、 最後のoldSize - (writePosition + data長さ) バイトをstream[[buffer]] に設定します。

        13. stream[[buffer]]headdatatailを連結したものに設定します。

        14. もしこれまでの手順でstream[[buffer]] を変更する操作がストレージクォータを超過したために失敗した場合、 "QuotaExceededError" DOMException を用いて拒否されたpを返し、これらの手順を中止し、 stream[[buffer]] を変更せずに残します。

          注: ストレージクォータバケットファイルシステム に保存されたファイルにのみ適用されます。しかし、この操作は他のファイルにも失敗する可能性があり、 例えば書き込み先のディスクがディスクスペース不足になった場合です。

        15. stream[[seekOffset]]writePosition + data長さ に設定します。

        16. 解決されたpを返します。

      4. それ以外の場合、もしcommandが"seek"の場合:

        1. 断言: chunk辞書である。

        2. もしchunk["position"] が存在しない場合、 拒否されたpTypeError として返し、この手順を中止します。

        3. stream[[seekOffset]]chunk["position"] に設定します。

        4. 解決されたpを返します。

      5. それ以外の場合、もしcommandが"truncate"の場合:

        1. 断言: chunk辞書である。

        2. もしchunk["size"] が存在しない場合、 拒否されたpTypeError として返し、この手順を中止します。

        3. newSizechunk["size"] に設定します。

        4. oldSizestream[[buffer]]長さに設定します。

        5. もしnewSizeoldSizeより大きい場合:

          1. stream[[buffer]] を、stream[[buffer]]newSize-oldSize分の 0x00バイトを含むバイト列を連結したものに設定します。

          2. もし前のステップの操作がストレージクォータ 超過のために失敗した場合、 拒否されたpを"QuotaExceededError" DOMException として返し、これらの手順を中止し、 stream[[buffer]] を変更せずに残します。

            注: ストレージクォータバケットファイルシステム に保存されたファイルにのみ適用されます。しかし、この操作は他のファイルにも失敗する可能性があり、 例えば書き込み先のディスクがディスクスペース不足になった場合です。

        6. それ以外の場合、もしnewSizeoldSizeより小さい場合:

          1. stream[[buffer]] を、stream[[buffer]] の最初のnewSizeバイトを含むバイト列に設定します。

        7. もしstream[[seekOffset]]newSizeより大きい場合、 stream[[seekOffset]]newSizeに設定します。

        8. 解決されたpを返します。

  4. pを返します。

2.5.1. The write() メソッド

await stream . write(data)
await stream . write({ type: "write", data: data })

dataの内容をstreamに関連付けられたファイルの現在のカーソル位置に書き込みます。

ストリームが閉じられるまで、実際のディスク上のファイルには変更は反映されません。 変更は通常、一時ファイルに書き込まれます。

await stream . write({ type: "write", position: position, data: data })

dataの内容をstreamに関連付けられたファイルの先頭からpositionバイトの位置に書き込みます。 また、現在のファイルカーソル位置を書き込まれたデータの末尾に更新します。

ストリームが閉じられるまで、実際のディスク上のファイルには変更は反映されません。 変更は通常、一時ファイルに書き込まれます。

await stream . write({ type: "seek", position: position })

現在のファイルカーソル位置を、ファイルの先頭からpositionバイトの位置に更新します。

await stream . write({ type: "truncate", size: size })

streamに関連付けられたファイルをsizeバイトの長さにリサイズします。 もしsizeが現在のファイルサイズより大きい場合、ファイルはヌルバイトでパディングされます。 それ以外の場合、ファイルは切り詰められます。

truncate が呼び出されたとき、ファイルカーソルが更新されます。 カーソルがsizeより小さい場合はそのままです。 カーソルがsizeより大きい場合は、後続の書き込みがエラーにならないようsizeに設定されます。

ストリームが閉じられるまで、実際のファイルには変更は反映されません。 変更は通常、一時ファイルに書き込まれます。

The write(data) メソッド の手順は以下の通りです:
  1. writerを、ライターを取得することでthisに対して取得します。

  2. resultを、writerに対してチャンクを書き込む 結果として設定します。

  3. ライターを解放する writer

  4. resultを返します。

2.5.2. The seek() メソッド

await stream . seek(position)

現在のファイルカーソル位置を、ファイルの先頭からpositionバイトの位置に更新します。

The seek(position) メソッドの手順は以下の通りです:
  1. writerを、ライターを取得することでthisに対して取得します。

  2. resultを、writerに対してチャンクを書き込む 結果として設定します。 «[ "type" → "seek", "position" → position ]».

  3. ライターを解放する writer

  4. resultを返します。

2.5.3. The truncate() メソッド

await stream . truncate(size)

streamに関連付けられたファイルをsizeバイトの長さにリサイズします。sizeが現在のファイルサイズより大きい場合、ファイルはヌルバイトでパディングされます。それ以外の場合、ファイルは切り詰められます。

truncate が呼び出されたとき、ファイルカーソルが更新されます。カーソルがsizeより小さい場合はそのままです。カーソルがsizeより大きい場合は、後続の書き込みがエラーにならないようsizeに設定されます。

ストリームが閉じられるまで、実際のファイルには変更は反映されません。変更は通常、一時ファイルに書き込まれます。

The truncate(size) メソッドの手順は以下の通りです:
  1. writerを、ライターを取得することでthisに対して取得します。

  2. resultを、writerに対してチャンクを書き込む 結果として設定します。 «[ "type" → "truncate", "size" → size ]».

  3. ライターを解放する writer

  4. resultを返します。

2.6. The FileSystemSyncAccessHandle インターフェイス

dictionary FileSystemReadWriteOptions {
  [EnforceRange] unsigned long long at;
};

[Exposed=DedicatedWorker, SecureContext]
interface FileSystemSyncAccessHandle {
  unsigned long long read(AllowSharedBufferSource buffer,
                          optional FileSystemReadWriteOptions options = {});
  unsigned long long write(AllowSharedBufferSource buffer,
                           optional FileSystemReadWriteOptions options = {});

  undefined truncate([EnforceRange] unsigned long long newSize);
  unsigned long long getSize();
  undefined flush();
  undefined close();
};

FileSystemSyncAccessHandle には関連付けられた [[file]]ファイルエントリ)があります。

FileSystemSyncAccessHandle には関連付けられた [[state]] があり、文字列 "open" または "closed" のいずれかのみを取ります。

FileSystemSyncAccessHandle は、単一のファイルに対して読み取り/書き込みを行い、そのサイズを取得および変更することができるオブジェクトです。

FileSystemSyncAccessHandle は同期メソッドを提供します。これにより、非同期操作に高いオーバーヘッドが伴うコンテキスト(例:WebAssembly)で高いパフォーマンスを実現できます。

FileSystemSyncAccessHandle には、ファイルの先頭からバイトオフセット0で初期化された ファイルポジションカーソル があります。

FileSystemSyncAccessHandle を新規作成するには、 ファイルエントリ fileRealm realm を指定して以下を実行します:
  1. handlenew された FileSystemSyncAccessHandle として realm 内で作成します。

  2. handle[[file]]file に設定します。

  3. handle[[state]] を "open" に設定します。

  4. handle を返します。

2.6.1. read() メソッド

handle . read(buffer)
handle . read(buffer, { at })

handle に関連付けられたファイルの内容を buffer に読み込みます。必要に応じて、指定されたオフセットで読み込みます。

read() が呼び出されると、ファイルカーソルが最後に読み込まれたバイトの次のバイトを指すように更新されます。

外部で変更されたファイルを読み取る際、アクセスハンドルがどのように反応するべきかを指定してください。[Issue #35]

read(buffer, FileSystemReadWriteOptions: options) メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、 スローします。 "InvalidStateError" DOMException を。

  2. bufferSizebufferバイト長に設定します。

  3. fileContentsthis[[file]]バイナリデータに設定します。

  4. fileSizefileContents長さに設定します。

  5. readStartoptions["at"] に設定します。もし options["at"] が 存在する場合です。それ以外の場合は thisファイルポジションカーソル に設定します。

  6. もし基盤となるファイルシステムが readStart での読み取りをサポートしていない場合、 スローします。TypeError を。

  7. もし readStartfileSize より大きい場合:

    1. thisファイルポジションカーソルfileSize に設定します。

    2. 0 を返します。

  8. readEndreadStart + (bufferSize − 1) に設定します。

  9. もし readEndfileSize より大きい場合、readEndfileSize に設定します。

  10. bytesバイトシーケンスで、 fileContentsreadStart から readEnd までのバイトを含むものに設定します。

  11. resultbytes長さに設定します。

  12. もし前述のステップで fileContents からの読み取り操作が失敗した場合:

    1. 部分的な読み取りがあり、bytes に読み込まれたバイト数がわかっている場合は、 result を読み取られたバイト数に設定します。

    2. それ以外の場合、result を 0 に設定します。

  13. arrayBufferbuffer基盤バッファに設定します。

  14. 書き込み bytesarrayBuffer に行います。

  15. thisファイルポジションカーソルreadStart + result に設定します。

  16. result を返します。

2.6.2. write() メソッド

handle . write(buffer)
handle . write(buffer, { at })

handle に関連付けられたファイルに buffer の内容を書き込みます。必要に応じて指定されたオフセットから書き込みを行い、書き込まれたバイト数を返します。 返された書き込まれたバイト数を確認することで、呼び出し元はエラーや部分的な書き込みを検出して処理することができます。

write() が呼び出されると、ファイルカーソルが最後に書き込まれたバイトの次のバイトを指すように更新されます。

write(buffer, FileSystemReadWriteOptions: options) メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、 スローします。 "InvalidStateError" DOMException を。

  2. writePositionoptions["at"] に設定します。もし options["at"] が 存在する場合です。それ以外の場合は thisファイルポジションカーソル に設定します。

  3. もし基盤となるファイルシステムが writePosition での書き込みをサポートしていない場合、 スローします。TypeError を。

  4. fileContentsthis[[file]]バイナリデータ のコピーに設定します。

  5. oldSizefileContents長さ に設定します。

  6. bufferSizebufferバイト長 に設定します。

  7. もし writePositionoldSize より大きい場合、 writePositionoldSize 分の 0x00 (NUL) バイトを fileContents の末尾に追加します。

    注: 実装はスキップされたファイル内容が実際に NUL バイトで埋められているかのように動作することが期待されます。 これらのバイトが実際にディスクに書き込まれディスクスペースを占有する必要はありません。 代わりに、多くのファイルシステムはスパースファイルをサポートしており、 これらの NUL バイトが実際のディスクスペースを占有しないようにすることができます。

  8. headバイトシーケンス で、 fileContents の先頭から writePosition バイト分を含むものに設定します。

  9. tail を空の バイトシーケンス に設定します。

  10. もし writePosition + bufferSizeoldSize より小さい場合:

    1. tailバイトシーケンス で、 fileContents の最後の oldSize − (writePosition + bufferSize) バイトを含むものに設定します。

  11. newSizehead長さ + bufferSize + tail長さ に設定します。

  12. もし newSizeoldSize が利用可能な ストレージクォータ を超える場合、 スロー します。 "QuotaExceededError" DOMException を。

  13. this[[file]]バイナリデータheadbuffer の内容、tail を連結したものに設定します。

    注: バッファーの内容にアクセスするメカニズムは意図的に曖昧にされています。 実装は、ホストオペレーティングシステムへの直接書き込みを実行することでパフォーマンスを重視する可能性が高く (バッファーのコピーを作成する代わりに)、書き込み順序と部分的な書き込みの結果の詳細な仕様を防ぎます。

  14. もし前述のステップで this[[file]]バイナリデータ を変更する操作が失敗した場合:

    1. 部分的な書き込みがあり、buffer から書き込まれたバイト数がわかっている場合:

      1. bytesWrittenbuffer から書き込まれたバイト数に設定します。

      2. thisファイルポジションカーソルwritePosition + bytesWritten に設定します。

      3. bytesWritten を返します。

    2. それ以外の場合、スロー します。 "InvalidStateError" DOMException を。

  15. thisファイルポジションカーソルwritePosition + bufferSize に設定します。

  16. bufferSize を返します。

2.6.3. truncate() メソッド

handle . truncate(newSize)

handle に関連付けられたファイルを newSize バイトの長さにリサイズします。newSize が現在のファイルサイズより大きい場合、ファイルはヌルバイトで埋められます。それ以外の場合、ファイルは切り詰められます。

truncate が呼び出されたとき、ファイルカーソルが更新されます。カーソルが newSize より小さい場合はそのままです。カーソルが newSize より大きい場合、newSize に設定されます。

truncate(newSize) メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、 スロー します。"InvalidStateError" DOMException を。

  2. fileContentsthis[[file]]バイナリデータ のコピーに設定します。

  3. oldSize長さ に設定します。this[[file]]バイナリデータ の。

  4. もし基盤となるファイルシステムが newSize へのサイズ設定をサポートしていない場合、 スロー します。TypeError を。

  5. もし newSizeoldSize より大きい場合:

    1. もし newSizeoldSize が利用可能な ストレージクォータ を超える場合、 スロー します。"QuotaExceededError" DOMException を。

    2. this[[file]] を次の バイトシーケンス に設定します。 これは fileContentsバイトシーケンス を連結したものです。このバイトシーケンスは newSizeoldSize 分の 0x00 バイトを含みます。

    3. もし前述のステップで this[[file]]バイナリデータ を変更する操作が失敗した場合、 スロー します。"InvalidStateError" DOMException を。

  6. それ以外の場合、もし newSizeoldSize より小さい場合:

    1. this[[file]] を次の バイトシーケンス に設定します。 これは fileContents の最初の newSize バイトを含みます。

    2. もし前述のステップで this[[file]]バイナリデータ を変更する操作が失敗した場合、 スロー します。"InvalidStateError" DOMException を。

  7. もし thisファイルポジションカーソルnewSize より大きい場合、ファイルポジションカーソルnewSize に設定します。

2.6.4. getSize() メソッド

handle . getSize()

handle に関連付けられたファイルのサイズをバイト単位で返します。

getSize() メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、 スロー します。"InvalidStateError" DOMException を。

  2. this[[file]]バイナリデータ長さ を返します。

2.6.5. flush() メソッド

handle . flush()

handle に関連付けられたファイルの内容が、write() を通じて行われたすべての変更を含むことを確認します。

flush() メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、 スロー します。"InvalidStateError" DOMException を。

  2. ファイルの内容に対するすべてのキャッシュされた変更を、ファイルシステムの基盤となるストレージデバイスに転送しようと試みます。

    注: これはフラッシュとも呼ばれます。一部のファイルシステム(例:インメモリファイルシステム)では、フラッシュする「ディスク」がないため、これは影響を与えない場合があります。

2.6.6. close() メソッド

handle . close()

アクセスハンドルを閉じるか、すでにアクセスハンドルが閉じられている場合は何もしません。これにより、以降の操作が無効になり、ロックが解除されます。handle に関連付けられた [[file]] の。

close() メソッドの手順は以下の通りです:
  1. もし this[[state]] が "closed" の場合、終了します。

  2. this[[state]] を "closed" に設定します。

  3. lockReleased を false に設定します。

  4. filethis[[file]] に設定します。

  5. 以下のステップをエンキューして ファイルシステムキュー に追加します:

    1. ロックを解除します。file の。

    2. lockReleased を true に設定します。

  6. 一時停止 します。lockReleased が true になるまで。

注: このメソッドは、ファイルのすべての変更が基盤となるストレージデバイスに即座に反映されることを保証するものではありません。この保証が必要な場合は、flush() メソッドを先に呼び出してください。

3. バケットファイルシステムへのアクセス

バケットファイルシステムは、 ストレージエンドポイントであり、その 識別子"fileSystem"タイプ« "local" »クォータはnullです。

ストレージエンドポイントは、[storage]自体で定義されるべきです。ここで定義するのではなく、そちらの表に統合してください。

注: ユーザーエージェントは通常、バケットファイルシステムの内容をディスクに永続化することでこれを実装しますが、内容が容易にユーザーがアクセス可能であることは意図されていません。同様に、バケットファイルシステムの子要素の名前と一致する名前を持つファイルやディレクトリが存在するという期待もありません。

[SecureContext]
partial interface StorageManager {
  Promise<FileSystemDirectoryHandle> getDirectory();
};
directoryHandle = await navigator . storage . getDirectory()

バケットファイルシステムのルートディレクトリを返します。

getDirectory() メソッドの手順は以下の通りです:
  1. environmentを、現在の設定オブジェクトとします。

  2. 次のパラメーターenvironmentおよび"fileSystem"を使用して、ローカルストレージボトルマップを取得を実行した結果をmapとします。これが失敗を返した場合、"SecurityError" DOMException拒否されたプロミスを返します。

  3. もしmap["root"]が存在しない場合:

    1. dirを、新しいディレクトリエントリとし、そのアクセスの照会および アクセスの要求アルゴリズムが常に ファイルシステムアクセス結果を返すものとします。 結果には、許可状態 "granted" と エラー名の空文字列を含むものとします。

    2. dir名前を空文字列に設定します。

    3. dir子要素を空の集合に設定します。

    4. map["root"]をdirに設定します。

  4. root実装依存の不透明な文字列とします。

  5. pathを« 空文字列 »とします。

  6. handleを、現在のRealmrootpathを用いて新しい FileSystemDirectoryHandleを作成する結果とします。

    注: rootには ストレージバケットなどの関連する識別情報が含まれる場合があります。

  7. 断言: エントリの位置特定handleロケーターを与えて実行した結果は、 map["root"]と同じエントリである ディレクトリエントリを返します。

  8. 解決されたPromiseとしてhandleを返します。

謝辞

感謝の意を表します: Alex Danilo、 Anne van Kesteren、 Anoesj Sadraee、 Austin Sullivan、 Chase Phillips、 Daseul Lee、 Dru Knox、 Edgar Chen、 Emanuel Krivoy、 Hazim Mohamed、 Ingvar Stepanyan、 Jari Jalkanen、 Joshua Bell、 Kagami Sascha Rosylight、 Marcos Cáceres、 Martin Thomson、 Olivier Yiptong、 Philip Jägenstedt、 Randell Jesup、 Richard Stotz、 Ruth John、 Sid Vishnoi、 Sihui Liu、 Stefan Sauer、 Thomas Steiner、 Victor Costan、および Youenn Fablet、 彼らの素晴らしさに対して!

この標準は Marijn Kruisselbrink (Google, mek@chromium.org) によって執筆されました。

知的財産権

この現行標準には、W3C WICG の File System Access からコピーされた素材が含まれており、 これは W3C ソフトウェアおよびドキュメントライセンス の下で利用可能です。

Copyright © WHATWG (Apple, Google, Mozilla, Microsoft)。この作品は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下でライセンスされています。これの一部がソースコードに組み込まれている場合、その部分はBSD 3-Clause ライセンスの下でライセンスされています。

これは現行標準です。特許レビュー版に興味のある方は、現行標準レビュー版をご覧ください。

索引

この仕様書で定義される用語

参照によって定義される用語

参考文献

規範的参照

[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding Standard. 現行標準. URL: https://encoding.spec.whatwg.org/
[FILE-API]
Marijn Kruisselbrink. File API. URL: https://w3c.github.io/FileAPI/
[HTML]
Anne van Kesteren; et al. HTML Standard. 現行標準. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. 現行標準. URL: https://infra.spec.whatwg.org/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/
[PERMISSIONS-REQUEST]
Requesting Permissions. Draft Community Group Report. URL: https://wicg.github.io/permissions-request/
[STORAGE]
Anne van Kesteren. Storage Standard. 現行標準. URL: https://storage.spec.whatwg.org/
[STREAMS]
Adam Rice; et al. Streams Standard. 現行標準. URL: https://streams.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 現行標準. URL: https://webidl.spec.whatwg.org/

IDL 索引

enum FileSystemHandleKind {
  "file",
  "directory",
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemHandle {
  readonly attribute FileSystemHandleKind kind;
  readonly attribute USVString name;

  Promise<boolean> isSameEntry(FileSystemHandle other);
};

dictionary FileSystemCreateWritableOptions {
  boolean keepExistingData = false;
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemFileHandle : FileSystemHandle {
  Promise<File> getFile();
  Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
  [Exposed=DedicatedWorker]
  Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
};

dictionary FileSystemGetFileOptions {
  boolean create = false;
};

dictionary FileSystemGetDirectoryOptions {
  boolean create = false;
};

dictionary FileSystemRemoveOptions {
  boolean recursive = false;
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemDirectoryHandle : FileSystemHandle {
  async_iterable<USVString, FileSystemHandle>;

  Promise<FileSystemFileHandle> getFileHandle(USVString name, optional FileSystemGetFileOptions options = {});
  Promise<FileSystemDirectoryHandle> getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});

  Promise<undefined> removeEntry(USVString name, optional FileSystemRemoveOptions options = {});

  Promise<sequence<USVString>?> resolve(FileSystemHandle possibleDescendant);
};

enum WriteCommandType {
  "write",
  "seek",
  "truncate",
};

dictionary WriteParams {
  required WriteCommandType type;
  unsigned long long? size;
  unsigned long long? position;
  (BufferSource or Blob or USVString)? data;
};

typedef (BufferSource or Blob or USVString or WriteParams) FileSystemWriteChunkType;

[Exposed=(Window,Worker), SecureContext]
interface FileSystemWritableFileStream : WritableStream {
  Promise<undefined> write(FileSystemWriteChunkType data);
  Promise<undefined> seek(unsigned long long position);
  Promise<undefined> truncate(unsigned long long size);
};

dictionary FileSystemReadWriteOptions {
  [EnforceRange] unsigned long long at;
};

[Exposed=DedicatedWorker, SecureContext]
interface FileSystemSyncAccessHandle {
  unsigned long long read(AllowSharedBufferSource buffer,
                          optional FileSystemReadWriteOptions options = {});
  unsigned long long write(AllowSharedBufferSource buffer,
                           optional FileSystemReadWriteOptions options = {});

  undefined truncate([EnforceRange] unsigned long long newSize);
  unsigned long long getSize();
  undefined flush();
  undefined close();
};


[SecureContext]
partial interface StorageManager {
  Promise<FileSystemDirectoryHandle> getDirectory();
};