文件和目录条目 API

社区组报告草案

此版本:
https://wicg.github.io/entries-api/
测试套件:
https://github.com/web-platform-tests/wpt/tree/master/entries-api
问题跟踪:
GitHub
规范内联
编辑者:
(谷歌公司)

摘要

本规范记录了通过拖放操作上传文件和目录的 Web 浏览器支持情况。它引入了表示目录的类型,并提供了用于异步遍历的方法,同时扩展了 HTMLInputElementDataTransferItem [HTML]

本文档状态

本规范由 Web 平台孵化器社区组 发布。 它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区贡献者许可协议 (CLA),存在有限的退出选项,并适用其他条件。 了解更多关于 W3C 社区和业务组 的信息。

1. 目标

本规范记录了当文件和目录的层级结构被拖放到页面上或通过表单元素选择时,Web 浏览器向脚本提供的类型和操作,或通过等效的用户操作。

这在很大程度上基于早期的 [file-system-api] 草案,该草案在沙箱文件系统的上下文中定义了类似的类型,包括用于创建和修改文件和目录的操作,但尚未被 Web 浏览器广泛采用。

注意:本文档描述的 API 最初在谷歌 Chrome 中实现。其他浏览器(目前包括 Edge、Firefox 和 Safari)正在开始支持 Chrome API 和行为的子集。本文档的目的是指定通用的子集,以确保这些实现具有互操作性。

2. 概念

2.1. 名称和路径

一个 名称 是一个字符串,满足以下条件:

一个 路径段 是一个 名称、'.'(U+002E FULL STOP)或 '..'(U+002E FULL STOP, U+002E FULL STOP)。

一个 相对路径 是一个由一个或多个 路径段 通过 '/'(U+002F SOLIDUS)连接而成的字符串,且不以 '/'(U+002F SOLIDUS)开头。

一个 绝对路径 是一个由 '/'(U+002F SOLIDUS)后跟零个或多个通过 '/'(U+002F SOLIDUS)连接的 路径段 组成的字符串。

一个 路径 是一个 相对路径 或一个 绝对路径

一个 有效路径 是一个 USVString ,它是一个 路径

2.2. 文件和目录

一个 文件 由二进制数据和一个 名称 (一个非空的 名称)组成。

一个 目录 由一个 名称(一个 名称)和一个有序的成员列表组成。每个成员要么是一个 文件,要么是一个 目录。一个 目录 的每个成员必须具有不同的非空 名称

一个 根目录 是一个 目录,它不是任何 目录 的成员。一个 根目录名称 是空的。

一个 父目录 是一个 文件目录 所属的 目录。一个 根目录 没有 父目录

编辑: 是否应将 目录 定义为 文件 的一种特殊类型,以便在 [HTML] 中仅需进行最小的更改?

注意:在大多数情况下,用户选择的文件和目录将由 API 以包含在一个 虚拟根目录 中的方式呈现,该虚拟根目录在与 API 交互的实际本地文件系统中并不存在。

一个 文件系统 由一个 名称 和一个 根目录 组成,根目录是一个关联的 根目录。一个 名称文件系统 是一个 USVString ,它由实现定义,但对于每个 文件系统 来说是唯一的。一个 根目录 仅与一个 文件系统 关联。

注意:实现可以通过为每个 文件系统 实例生成带有一些固定前缀和后缀字符串的 UUID 来生成一个 名称。使用 API 的作者被建议不要对名称的结构或内容做出假设。

2.3. 条目

一个 条目 要么是一个 文件条目,要么是一个 目录条目

一个 条目 具有一个 名称(一个 名称)和一个 完整路径(一个 绝对路径)。

一个 条目 还具有一个 根目录, 它是一个关联的 根目录

注意: 条目 是相对于一个 路径 和一个 根目录 定义的,以考虑到支持与 API 交互的本地文件系统在枚举目录内容等操作期间可能会被异步修改的事实。在这些情况下,对 条目 上暴露的操作将产生错误,因为 路径 不再引用相同的实体。

一个 文件系统 是一个 条目 所属的 文件系统,它与该 条目根目录 关联。

3. 算法

要使用 abspath(一个 绝对路径)和 path(一个 绝对路径、一个 相对路径,或空字符串)来 解析相对路径, 执行以下步骤。它们返回一个 绝对路径

  1. 如果 path 是一个 绝对路径,则返回 path

  2. abspath segments严格分割 abspath 在 '/'(U+002F SOLIDUS)上的结果。

    注意:第一个字符串将是空的。

  3. path segments严格分割 path 在 '/'(U+002F SOLIDUS)上的结果。

  4. 对于 path segments 中的每个 segment,根据 segment 进行切换:

    空字符串

    继续。

    '.'(U+002E FULL STOP)

    继续。

    '..'(U+002E FULL STOP, U+002E FULL STOP)

    移除 abspath segments 的最后一个成员,除非它是唯一的成员。

    其他情况

    segment 追加到 abspath segments

  5. 返回由 '/'(U+002F SOLIDUS)连接的 abspath segments

要使用 directory(一个 根目录)和 path(一个 绝对路径)来 评估路径, 执行以下步骤。它们返回一个 文件目录,或失败。

  1. segments严格分割 path 在 '/'(U+002F SOLIDUS)上的结果。

  2. segments 中移除第一个条目。

    注意:由于 path 是一个 绝对路径, 这个第一个条目将始终是空的。

  3. 对于 segments 中的每个 segment,根据 segment 进行切换:

    空字符串

    继续。

    '.'(U+002E FULL STOP)

    继续。

    '..'(U+002E FULL STOP, U+002E FULL STOP)

    directory 成为 directory父目录,或者如果没有则保持 directory 不变。

    其他情况

    执行以下步骤:

    1. item 成为 directory 中名称等于 segment 的成员,如果没有则返回失败。

    2. 如果 segmentsegments 中的最后一项,则返回 item

    3. 如果 item 是一个 文件,则返回失败。

    4. directory 成为 item

4. File 接口

编辑: 完成本节后,应将其合并到 [FileAPI] 中。
partial interface File {
    readonly attribute USVString webkitRelativePath;
};

webkitRelativePath 的 getter 步骤是返回 this相对路径,如果未指定则返回空字符串。

5. HTML:表单

编辑: 完成本节后,应将其合并到 [HTML] 中。诸如 构造条目列表 的步骤需要扩展以包括 webkitRelativePath 属性。
partial interface HTMLInputElement {
    attribute boolean webkitdirectory;
    readonly attribute FrozenArray<FileSystemEntry> webkitEntries;
};

当一个 input 元素的 type 属性处于 文件上传 状态时,本节中的规则适用。

webkitEntries IDL 属性允许脚本访问元素所选的条目。获取时,如果 IDL 属性适用,则必须返回一个包含当前 所选文件(包括允许的目录)的 FileSystemEntry 对象的数组。如果 IDL 属性不适用,则必须返回 null。

使用 webkitEntries 枚举条目:
<input id=a type=file multiple>
document.querySelector('#a').addEventListener('change', e => {
  for (const entry of e.target.webkitEntries) {
    handleEntry(entry);
  }
});
互操作性: 在 Chrome 中,webkitEntries 仅在拖放操作的结果中填充,而不是在点击元素时填充。我们是否应该修复此问题,使其始终被填充?
互操作性: 在 Chrome 中,如果在 webkitdirectory 上指定了 HTMLInputElementwebkitEntries 不会被填充;必须使用 files 集合和 webkitRelativePath 属性来重建目录结构。我们是否应该修复此问题,使其始终被填充?

6. HTML:拖放

编辑: 完成本节后,应将其合并到 [HTML] 中。

拖放操作 期间,文件目录 项与 条目 关联。每个 条目 是一个独属于 根目录拖放数据存储 的成员。

此外,每个 目录 项在 拖放数据存储项目列表 中表示为一种 类型文件 的项。如果通过 getAsFile() 访问,则返回一个零长度的 File

注意:用户代理可以在拖放操作期间将任何层级数据表示为文件和目录。例如,在一个不直接向用户公开本地文件系统的设备上,如果为 "image/*" 指定了 accept 属性,则存储在关系数据库中的音频数据(具有用于专辑元数据的单独表和用于曲目的 Blob)可以在从媒体播放器应用程序拖动时作为目录和文件暴露给脚本。

partial interface DataTransferItem {
    FileSystemEntry? webkitGetAsEntry();
};

webkitGetAsEntry() 方法步骤如下:

  1. storethisDataTransfer 对象的 拖放数据存储

  2. 如果 store拖放数据存储模式 不是 读/写模式只读模式,则返回 null 并中止这些步骤。

  3. itemstore拖放数据存储项目列表 中代表 this 的项目。

  4. 如果 item类型 不是 文件,则返回 null 并中止这些步骤。

  5. 返回一个新的 FileSystemEntry 对象,表示该 条目

处理文件和目录的拖放:
elem.addEventListener('dragover', e => {
  // 防止导航。
  e.preventDefault();
});
elem.addEventListener('drop', e => {
  // 防止导航。
  e.preventDefault();

  // 处理所有项目。
  for (const entry of e.dataTransfer.items) {
    // kind 对于文件/目录条目将是 'file'。
    if (item.kind === 'file') {
      const entry = item.webkitGetAsEntry();
      handleEntry(entry);
    }
  }
});

7. 文件和目录

网络兼容性: 旧的 TypeMismatchError 已在大多数 规范中被 TypeError 所取代, 但名称不同。我们是否可以在这里也进行切换以保持兼容性?
callback ErrorCallback = undefined (DOMException err);

一个 ErrorCallback 函数用于可能异步返回错误的操作。

互操作性: 用于以下步骤中 排队的任务任务源 未定义。基于 Chromium 的浏览器似乎使用以下内容:

7.1. FileSystemEntry 接口

[Exposed=Window]
interface FileSystemEntry {
    readonly attribute boolean isFile;
    readonly attribute boolean isDirectory;
    readonly attribute USVString name;
    readonly attribute USVString fullPath;
    readonly attribute FileSystem filesystem;

    undefined getParent(optional FileSystemEntryCallback successCallback,
                   optional ErrorCallback errorCallback);
};

一个 FileSystemEntry 关联一个 条目

isFile 的 getter 步骤是如果 this 是一个 文件条目,则返回 true,否则返回 false。

isDirectory 的 getter 步骤是如果 this 是一个 目录条目,则返回 true,否则返回 false。

name 的 getter 步骤是返回 this名称

fullPath 的 getter 步骤是返回 this完整路径

filesystem 的 getter 步骤是返回 this文件系统

getParent(successCallback, errorCallback) 方法步骤如下:

  1. 并行执行以下步骤:

    1. path 为使用 this完整路径和“..”解析相对路径的结果。

    2. item 为使用 thispath 计算路径的结果。

    3. 如果 item 失败,将一个任务排队以使用 « 一个新创建的“NotFoundErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    4. entry 为一个新的目录条目,其名称item名称完整路径path

    5. 将一个任务排队以使用 « 一个与 entry 关联的新 FileSystemDirectoryEntry 对象 » 和“report调用 successCallback

注意:如果文件在创建 FileSystemEntry 之后在磁盘上被修改,则可能会出错。

处理一个条目:
function handleEntry(entry) {
      console.log('name: ' + entry.name);
      console.log('path: ' + entry.fullPath);
      if (entry.isFile) {
        console.log('... is a file');
      } else if (entry.isDirectory) {
        console.log('... is a directory');
      }
    }
    
辅助函数,将 getParent() 适配为与 Promises [ECMA-262] 一起使用:
function getParentAsPromise(entry) {
      return new Promise((resolve, reject) => {
        entry.getParent(resolve, reject);
      });
    }

7.2. FileSystemDirectoryEntry 接口

[Exposed=Window]
interface FileSystemDirectoryEntry : FileSystemEntry {
    FileSystemDirectoryReader createReader();
    undefined getFile(optional USVString? path,
                 optional FileSystemFlags options = {},
                 optional FileSystemEntryCallback successCallback,
                 optional ErrorCallback errorCallback);
    undefined getDirectory(optional USVString? path,
                      optional FileSystemFlags options = {},
                      optional FileSystemEntryCallback successCallback,
                      optional ErrorCallback errorCallback);
};
    
dictionary FileSystemFlags {
    boolean create = false;
    boolean exclusive = false;
};
    
callback FileSystemEntryCallback = undefined (FileSystemEntry entry);

注意:虽然指定标志时没有有用的行为,但为了与现有实现兼容,create 成员及其相关行为已包含在内。同样,exclusive 成员未被明确引用,但如果传递一个带有 getter 的对象,绑定行为将在脚本中可观察到。

一个 FileSystemDirectoryEntry 的 关联 条目 是一个 目录条目

createReader() 方法步骤是:

  1. 返回一个新创建的 FileSystemDirectoryReader 对象,该对象 关联到 目录条目

getFile(path, options, successCallback, errorCallback) 方法的步骤如下:

  1. 并行执行以下步骤:

    1. 如果 path 是 undefined 或 null,则令 path 为空字符串。

    2. 如果 path 不是一个有效路径将一个任务排队以使用 « 一个新创建的“TypeMismatchErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    3. 如果 optionscreate 成员为 true,将一个任务排队以使用 « 一个新创建的“SecurityErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    4. path 为使用 this完整路径path 解析相对路径的结果。

    5. item 为使用 thispath 计算路径的结果。

    6. 如果 item 失败,将一个任务排队以使用 « 一个新创建的“NotFoundErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    7. 如果 item 不是一个文件将一个任务排队以使用 « 一个新创建的“TypeMismatchErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    8. entry 为一个新的文件条目,其名称item名称完整路径path

    9. 将一个任务排队以使用 « 一个与 entry 关联的新 FileSystemFileEntry 对象 » 和“report调用 successCallback(如果已提供)。

getDirectory(path, options, successCallback, errorCallback) 方法的步骤如下:

  1. 并行执行以下步骤:

    1. 如果 path 是 undefined 或 null,则令 path 为空字符串。

    2. 如果 path 不是一个有效路径将一个任务排队以使用 « 一个新创建的“TypeMismatchErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    3. 如果 optionscreate 成员为 true,将一个任务排队以使用 « 一个新创建的“SecurityErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    4. path 为使用 this完整路径path 解析相对路径的结果。

    5. item 为使用 thispath 计算路径的结果。

    6. 如果 item 失败,将一个任务排队以使用 « 一个新创建的“NotFoundErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    7. 如果 item 不是一个目录调用 errorCallback(如果已提供)并附带 « 一个新创建的“TypeMismatchErrorDOMException » 和“report”,并中止这些步骤。

    8. entry 为一个新的目录条目,其名称item名称完整路径path

    9. 将一个任务排队以使用 « 一个与 entry 关联的新 FileSystemDirectoryEntry 对象 » 和“report调用 successCallback(如果已提供)。

辅助函数,将 getFile()getDirectory() 适配为与 Promises [ECMA-262] 一起使用:
function getFileAsPromise(entry, path) {
  return new Promise((resolve, reject) => {
    entry.getFile(path, {}, resolve, reject);
  });
}
function getDirectoryAsPromise(entry, path) {
  return new Promise((resolve, reject) => {
    entry.getDirectory(path, {}, resolve, reject);
  });
}

7.3. FileSystemDirectoryReader 接口

[Exposed=Window]
interface FileSystemDirectoryReader {
    undefined readEntries(FileSystemEntriesCallback successCallback,
                     optional ErrorCallback errorCallback);
};
callback FileSystemEntriesCallback = undefined (sequence<FileSystemEntry> entries);
一个 FileSystemDirectoryReader 关联一个 条目(一个 目录条目), 一个 目录(初始为 null), 一个 读取标志(初始为 false), 一个 完成标志(初始为 false), 以及一个 读取器错误(初始为 null)。

readEntries(successCallback, errorCallback) 方法的步骤如下:

  1. 如果 this读取标志为 true,将一个任务排队以使用 « 一个新创建的“InvalidStateErrorDOMException » 和“report调用 errorCallback,并中止这些步骤。

  2. 如果 this读取器错误不为 null,将一个任务排队以使用 « 读取器错误 » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

  3. 如果 this完成标志为 true,将一个任务排队以使用一个空列表和“report调用 successCallback,并中止这些步骤。

  4. this读取标志设置为 true。

  5. 并行执行以下步骤:

    1. 如果 this目录为 null,则:

      1. dir 为使用 this条目完整路径计算路径的结果。

      2. 如果 dir 失败,则:

        1. 将一个任务排队以运行以下步骤:

          1. error 为一个新创建的“NotFoundErrorDOMException

          2. this读取器错误设置为 error

          3. this读取标志设置为 false。

          4. 调用 errorCallback(如果已提供)并附带 « error » 和“report”。

        2. 中止这些步骤。

      3. this目录设置为 dir

    2. entriesthis目录中尚未由此 FileSystemDirectoryReader 生成的非零数量的条目(如果有)。

    3. 如果上一步失败(例如,目录被删除或权限被拒绝),则:

      1. 将一个任务排队以运行以下步骤:

        1. error 为一个适当的 DOMException

        2. this读取器错误设置为 error

        3. this读取标志设置为 false。

        4. 调用 errorCallback(如果已提供)并附带 « error » 和“report”。

      2. 中止这些步骤。

    4. 将一个任务排队以运行以下步骤:

      1. 如果 entries 为空,则将 this完成标志设置为 true。

      2. this读取标志设置为 false。

      3. 调用 successCallback 并附带 « entries » 和“report”。

注意:使用读取标志可以防止上述并行步骤的多个副本同时执行。这消除了指定并行队列的需要。

枚举一个目录:
const reader = dirEntry.createReader();
const doBatch = () => new Promise((resolve, reject) => {
  // 读取一个批次。
  reader.readEntries(entries => {
  
    // 完成了吗?
    if (entries.length === 0) {
      return;
    }
  
    // 处理这个批次。
    entries.forEach(handleEntry);
  
    // 读取下一个批次。
    doBatch();
  
  }, error => console.warn(error));
};
  
// 开始读取
doBatch();
辅助函数,将 FileSystemDirectoryReader 适配为与 Promises [ECMA-262] 一起使用:
function getEntriesAsPromise(dirEntry) {
  return new Promise((resolve, reject) => {
    const result = [];
    const reader = dirEntry.createReader();
    const doBatch = () => {
      reader.readEntries(entries => {
        if (entries.length > 0) {
          entries.forEach(e => result.push(e));
          doBatch();
        }
  
        else {
          resolve(result);
        }
      }, reject);
    };
    doBatch();
  });
}
辅助函数,将 FileSystemDirectoryReader 适配为与 AsyncIterators [ECMA-262] 一起使用:
async function* getEntriesAsAsyncIterator(dirEntry) {
  const reader = dirEntry.createReader();
  const getNextBatch = () => new Promise((resolve, reject) => {
    reader.readEntries(resolve, reject);
  });
  
  let entries;
  do {
    entries = await getNextBatch();
    for (const entry of entries) {
      yield entry;
    }
  } while (entries.length > 0);
}

这允许使用 for-await-of 进行有序的异步遍历目录树:

async function show(entry) {
  console.log(entry.fullPath);
  if (entry.isDirectory) {
    for await (const e of getEntriesAsAsyncIterator(entry)) {
      await show(e);
    }
  }
}

7.4. FileSystemFileEntry 接口

[Exposed=Window]
interface FileSystemFileEntry : FileSystemEntry {
    undefined file(FileCallback successCallback,
              optional ErrorCallback errorCallback);
};
callback FileCallback = undefined (File file);

A FileSystemFileEntry 的 关联 条目 是一个 文件条目

file(successCallback, errorCallback) 方法的步骤如下:

  1. 并行执行以下步骤:

    1. item 为使用 this完整路径计算路径的结果。

    2. 如果 item 失败,将一个任务排队以使用 « 一个新创建的“NotFoundErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    3. 如果 item 是一个目录将一个任务排队以使用 « 一个新创建的“TypeMismatchErrorDOMException » 和“report调用 errorCallback(如果已提供),并中止这些步骤。

    4. 将一个任务排队以使用 « 一个代表 item 的新 File 对象 » 和“report调用 successCallback

使用 FileReader 读取拖放文件的内容:
function readFileEntry(entry) {
  entry.file(file => {
    const reader = new FileReader();
    reader.readAsText(file);
    reader.onerror = error => console.warn(error);
    reader.onload = () => {
      console.log(reader.result);
    };
  }, error => console.warn(error));
}
用于将 file() 适配到 Promises [ECMA-262] 使用的辅助函数:
function fileAsPromise(entry) {
  return new Promise((resolve, reject) => {
    entry.file(resolve, reject);
  });
}

7.5. FileSystem 接口

[Exposed=Window]
interface FileSystem {
    readonly attribute USVString name;
    readonly attribute FileSystemDirectoryEntry root;
};

一个 FileSystem 的 关联 文件系统

name 的 getter 步骤是返回 this名称

root 的 getter 步骤是返回一个与 this根目录 关联的 FileSystemDirectoryEntry 对象。

8. 致谢

本规范在很大程度上基于 Eric Uhrhane 在 [file-system-api] 中的工作, 该工作引入了 FileSystemEntry 类型。

感谢 Tab Atkins, Jr. 创建和维护 Bikeshed,这是用于创建本文件的规范编写工具。

还要感谢 Ali Alabbas, Philip Jägenstedt, Marijn Kruisselbrink, Olli Pettay, 和 Kent Tamura 提供的建议、审查和其他反馈。

符合性

文档约定

符合性要求通过描述性断言和 RFC 2119 术语的组合来表达。 本文件规范性部分中的关键字 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 和 “OPTIONAL” 应按照 RFC 2119 中所述进行解释。 然而,为了提高可读性, 这些词在本规范中不会全部以大写字母出现。

本规范的所有文本都是规范性的, 除了明确标记为非规范性的部分、示例和注释。 [RFC2119]

本规范中的示例以 “例如” 开头, 或者通过 class="example" 与规范性文本区分开, 如下所示:

这是一个信息性示例的例子。

信息性注释以 “注意” 开头, 并通过 class="note" 与规范性文本区分开, 如下所示:

注意,这是一个信息性注释。

索引

本规范定义的术语

参考定义的术语

参考文献

规范性参考文献

[FileAPI]
Marijn Kruisselbrink. File API. URL: https://w3c.github.io/FileAPI/
[HTML]
Anne van Kesteren; 等人. HTML 标准. 活跃标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 活跃标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFC 中用于指示需求级别的关键字. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 活跃标准. URL: https://webidl.spec.whatwg.org/

信息性参考文献

[ECMA-262]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[FILE-SYSTEM-API]
Eric Uhrhane. File API: 目录和系统. URL: https://dev.w3.org/2009/dap/file-system/file-dir-sys.html

IDL 索引

partial interface File {
    readonly attribute USVString webkitRelativePath;
};

partial interface HTMLInputElement {
    attribute boolean webkitdirectory;
    readonly attribute FrozenArray<FileSystemEntry> webkitEntries;
};

partial interface DataTransferItem {
    FileSystemEntry? webkitGetAsEntry();
};

callback ErrorCallback = undefined (DOMException err);

[Exposed=Window]
interface FileSystemEntry {
    readonly attribute boolean isFile;
    readonly attribute boolean isDirectory;
    readonly attribute USVString name;
    readonly attribute USVString fullPath;
    readonly attribute FileSystem filesystem;

    undefined getParent(optional FileSystemEntryCallback successCallback,
                   optional ErrorCallback errorCallback);
};

[Exposed=Window]
interface FileSystemDirectoryEntry : FileSystemEntry {
    FileSystemDirectoryReader createReader();
    undefined getFile(optional USVString? path,
                 optional FileSystemFlags options = {},
                 optional FileSystemEntryCallback successCallback,
                 optional ErrorCallback errorCallback);
    undefined getDirectory(optional USVString? path,
                      optional FileSystemFlags options = {},
                      optional FileSystemEntryCallback successCallback,
                      optional ErrorCallback errorCallback);
};

dictionary FileSystemFlags {
    boolean create = false;
    boolean exclusive = false;
};

callback FileSystemEntryCallback = undefined (FileSystemEntry entry);

[Exposed=Window]
interface FileSystemDirectoryReader {
    undefined readEntries(FileSystemEntriesCallback successCallback,
                     optional ErrorCallback errorCallback);
};
callback FileSystemEntriesCallback = undefined (sequence<FileSystemEntry> entries);

[Exposed=Window]
interface FileSystemFileEntry : FileSystemEntry {
    undefined file(FileCallback successCallback,
              optional ErrorCallback errorCallback);
};
callback FileCallback = undefined (File file);

[Exposed=Window]
interface FileSystem {
    readonly attribute USVString name;
    readonly attribute FileSystemDirectoryEntry root;
};

问题索引

编辑: 是否应将 目录 定义为 文件 的一种特殊类型,以便在 [HTML] 中需要的更改最小?
编辑: 一旦完成,本节应合并到 [FileAPI] 中。
编辑: 一旦完成,本节应合并到 [HTML] 中。 诸如 构建 条目列表 的步骤需要扩展以包括 webkitRelativePath 属性。
互操作性: 在 Chrome 中, webkitEntries 仅作为拖放操作的结果填充,而不是当元素被点击时。我们是否应该修复这个问题,使其始终被填充?
互操作性: 在 Chrome 中,如果 webkitdirectory 被指定在一个 HTMLInputElementwebkitEntries 不会被填充;必须使用 files 集合和 webkitRelativePath 属性来重建目录结构。我们是否应该修复这个问题,使其始终被填充?
编辑: 一旦完成,本节应合并到 [HTML] 中。
网络兼容: 旧的 TypeMismatchError 在大多数 规范中已被 TypeError 所取代, 但名称不同。我们是否可以在这里也进行切换以保持兼容性?
用于下列步骤中 任务 源排队的任务 未被定义。基于 Chromium 的浏览器似乎使用以下内容:
MDN

DataTransferItem/webkitGetAsEntry

In all current engines.

Firefox50+Safari11.1+Chrome13+
Opera?Edge79+
Edge (Legacy)14+IENone
Firefox for AndroidNoneiOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

File/webkitRelativePath

In all current engines.

Firefox50+Safari11.1+Chrome13+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystem/name

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystem/root

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystem

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryEntry/createReader

In all current engines.

Firefox50+Safari11.1+Chrome13+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryEntry/getDirectory

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryEntry/getFile

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryReader/readEntries

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemDirectoryReader

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/filesystem

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/fullPath

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/getParent

In all current engines.

Firefox52+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/isDirectory

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/isFile

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry/name

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemFileEntry/file

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

FileSystemFileEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

HTMLInputElement/webkitdirectory

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for AndroidNoneiOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

HTMLInputElement/webkitEntries

In all current engines.

Firefox50+Safari11.1+Chrome22+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for AndroidNoneiOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?