Storage API

应用开发的几乎每个方面都涉及发送或接收数据的一些元素。从基础知识开始,您应使用 MVC 框架来帮助您设计和实现应用,以使数据与在该数据上的应用视图完全分开(请参阅 MVC 架构)。

您还需要考虑应用在离线状态下如何处理数据(请参阅离线优先)。 本文档简要介绍了用于在本地发送、接收和保存数据的存储选项;文档的其余部分介绍了如何使用 Chrome 的 File System API 和 Sync File System API(另请参阅 fileSystem APIsyncFileSystem API)。

存储选项

打包应用程序使用许多不同的机制来发送和接收数据。对于外部数据(资源、网页),您需要了解内容安全政策 (CSP)。与 Chrome 扩展程序类似,您可以使用跨源 XMLHttpRequests 与远程服务器进行通信。您还可以隔离外部页面,以确保应用的其余部分安全无虞(请参阅嵌入外部网页)。

在本地保存数据时,您可以使用 Chrome Storage API 保存少量字符串数据,并使用 IndexedDB 保存结构化数据。借助 IndexedDB,您可以将 JavaScript 对象保留在对象存储区中,并使用存储区的索引来查询数据(如需了解详情,请参阅 HTML5 Rock 的简单待办事项列表教程)。对于所有其他类型的数据(如二进制数据),请使用 Filesystem and Sync Filesystem API。

Chrome 的 Filesystem API 和 Sync Filesystem API 扩展了 HTML5 FileSystem API。借助 Chrome 的 Filesystem API,应用可以在用户本地文件系统的沙盒化部分创建、读取、浏览和写入数据。例如,照片分享应用可以使用 Filesystem API 读取和写入用户选择的任何照片。

借助 Chrome 的 Sync Filesystem API,应用可以在用户的 Google 云端硬盘中保存和同步数据,从而在不同客户端中提供相同的数据。例如,云端文本编辑器应用可以自动将新的文本文件同步到用户的 Google 云端硬盘帐号。当用户在新客户端中打开文本编辑器时,Google 云端硬盘会将新的文本文件推送到该文本编辑器实例。

使用 Chrome Filesystem API

正在添加文件系统权限

如需使用 Chrome 的 File System API,您需要向清单中添加“fileSystem”权限,以便您可以从用户那里获取存储持久性数据的权限。

"permissions": [
  "...",
  "fileSystem"
]

用于选择文件的用户选项

用户希望像往常一样选择文件。他们至少需要一个“选择文件”按钮和标准的文件选择器。如果您的应用大量使用文件处理功能,则您还应实现拖放操作(请参阅下文,另请参阅原生 HTML5 拖放)。

获取 fileEntry 的路径

如需获取用户所选文件 fileEntry 的完整路径,请调用 getDisplayPath()

function displayPath(fileEntry) {
  chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
    console.log(path)
  });
}

实现拖放

如果您需要实现拖放选择,不妨从文件系统访问示例中的拖放文件控制器 (dnd.js) 着手。控制器会通过拖放操作从 DataTransferItem 创建文件条目。在此示例中,fileEntry 设置为第一项被丢弃的项。

var dnd = new DnDFileController('body', function(data) {
  var fileEntry = data.items[0].webkitGetAsEntry();
  displayPath(fileEntry);
});

读取文件

以下代码会打开文件(只读),并使用 FileReader 对象以文本形式读取该文件。如果该文件不存在,则会抛出错误。

var chosenFileEntry = null;

chooseFileButton.addEventListener('click', function(e) {
  chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {

    readOnlyEntry.file(function(file) {
      var reader = new FileReader();

      reader.onerror = errorHandler;
      reader.onloadend = function(e) {
        console.log(e.target.result);
      };

      reader.readAsText(file);
    });
    });
});

写入文件

写入文件的两种常见用例是“保存”和“另存为”。以下代码会从只读 chosenFileEntry 创建 writableEntry,并将所选文件写入其中。

 chrome.fileSystem.getWritableEntry(chosenFileEntry, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = callback;

    chosenFileEntry.file(function(file) {
      writer.write(file);
    });
  }, errorHandler);
});

以下代码会创建一个具有“另存为”功能的新文件,并使用 writer.write() 方法将新的 blob 写入该文件。

chrome.fileSystem.chooseEntry({type: 'saveFile'}, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = function(e) {
        console.log('write complete');
      };
      writer.write(new Blob(['1234567890'], {type: 'text/plain'}));
    }, errorHandler);
});

使用 Chrome Sync Filesystem API

使用可同步的文件存储,返回的数据对象可以像 FileSystem API 中的本地离线文件系统一样操作,但添加了这些数据(并自动)同步到 Google 云端硬盘。

正在添加同步文件系统权限

如需使用 Chrome 的 Sync Filesystem API,您需要在清单中添加“syncFileSystem”权限,以便您可以从用户那里获取存储和同步持久性数据的权限。

"permissions": [
  "...",
  "syncFileSystem"
]

启动可同步的文件存储

如需在您的应用中启动可同步文件存储,只需调用 syncFileSystem.requestFileSystem 即可。 此方法会返回由 Google 云端硬盘支持的可同步文件系统,例如:

chrome.syncFileSystem.requestFileSystem(function (fs) {
   // FileSystem API should just work on the returned 'fs'.
   fs.root.getFile('test.txt', {create:true}, getEntryCallback, errorCallback);
});

文件同步状态简介

使用 syncFileSystem.getFileStatus 获取当前文件的同步状态:

chrome.syncFileSystem.getFileStatus(entry, function(status) {...});

文件同步状态值可以是以下值之一:'synced''pending''conflicting'。 “已同步”表示文件已完全同步;没有尚未同步到 Google 云端硬盘的待处理本地更改。但是,Google 云端硬盘中可能有尚未提取的待处理更改。

“待处理”表示文件包含尚未同步到 Google 云端硬盘的待处理更改。如果应用在线运行,本地更改(几乎)会立即同步到 Google 云端硬盘,并且会触发 syncFileSystem.onFileStatusChanged 事件,并显示 'synced' 状态(如需了解详情,请参阅下文)。

文件状态更改为 'conflicting' 时,会触发 syncFileSystem.onFileStatusChanged。“冲突”表示本地存储空间和 Google 云端硬盘中有冲突的更改。仅当冲突解决政策设置为 'manual' 时,文件才能处于此状态。默认政策为 'last_write_win',冲突会自动通过简单的最终写出政策来解决。可以通过 syncFileSystem.setConflictResolutionPolicy 更改系统的冲突解决政策。

如果冲突解决政策设置为 'manual' 且文件导致 'conflicting' 状态,应用仍然可以将文件作为本地离线文件读取和写入,但不会同步更改,并且文件将与其他客户端上执行的远程更改保持分离,直到冲突解决。解决冲突的最简单方法是删除或重命名文件的本地版本。 这会强制同步远程版本,解决冲突状态,并以 'synced' 状态触发 onFileStatusChanged 事件。

正在监听同步状态的变化

当文件的同步状态发生更改时,会触发 syncFileSystem.onFileStatusChanged 事件。 例如,假设某个文件包含待更改项且处于“待处理”状态。应用可能处于离线状态,因此更改即将同步。当同步服务检测到待处理的本地更改并将更改上传到 Google 云端硬盘时,该服务会触发带有以下值的 onFileStatusChanged 事件:{ fileEntry:a fileEntry for the file, status: 'synced', action: 'updated', direction: 'local_to_remote' }

同样,无论本地 activity 如何,同步服务都可以检测其他客户端所做的远程更改,并将更改从 Google 云端硬盘下载到本地存储空间。如果远程更改是为了添加新文件,则会触发包含以下值的事件:{ fileEntry: a fileEntry for the file, status: 'synced', action: 'added', direction: 'remote_to_local' }

如果本地端和远程端对同一文件的更改存在冲突,并且冲突解决政策设置为 'manual',则文件状态将更改为 conflicting 状态,与同步服务分离,并且在冲突解决之前不会同步。在这种情况下,会触发具有以下值的事件:{ fileEntry: a fileEntry for the file, status: 'conflicting', action: null, direction: null }

您可以为此事件添加监听器,用于响应状态的任何更改。例如,Chrome 音乐播放器应用会监听从 Google 云端硬盘同步的任何新音乐,但尚未将它们导入到特定客户端上的用户本地存储空间。找到的任何音乐都会同步到该客户端:

chrome.syncFileSystem.onFileStatusChanged.addListener(function(fileInfo) {
  if (fileInfo.status === 'synced') {
    if (fileInfo.direction === 'remote_to_local') {
      if (fileInfo.action === 'added') {
        db.add(fileInfo.fileEntry);
      } else if (fileInfo.action === 'deleted') {
        db.remove(fileInfo.fileEntry);
      }
    }
  }
});

检查 API 使用情况

如需查看 API 当前使用的数据量,请查询应用的本地沙盒化目录或 syncFileSystem.getUsageAndQuota 返回的用量字节数:

chrome.syncFileSystem.getUsageAndQuota(fileSystem, function (storageInfo) {
   updateUsageInfo(storageInfo.usageBytes);
   updateQuotaInfo(storageInfo.quotaBytes);
});

您还可以查看用户的同步后端服务存储空间(在 Google 云端硬盘中)。已同步的文件保存在隐藏的 Google 云端硬盘文件夹 Chrome Syncable FileSystem 中。该文件夹不会显示在“我的云端硬盘”列表中,但您可以通过在搜索框中搜索文件夹名称来访问该文件夹。(请注意,保证远程文件夹布局在各个版本之间保持向后兼容)。