应用开发的几乎每个方面都涉及发送或接收数据的一些元素。从基础知识开始,您应使用 MVC 框架来帮助您设计和实现应用,以使数据与在该数据上的应用视图完全分开(请参阅 MVC 架构)。
您还需要考虑应用在离线状态下如何处理数据(请参阅离线优先)。 本文档简要介绍了用于在本地发送、接收和保存数据的存储选项;文档的其余部分介绍了如何使用 Chrome 的 File System API 和 Sync File System API(另请参阅 fileSystem API 和 syncFileSystem 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 中。该文件夹不会显示在“我的云端硬盘”列表中,但您可以通过在搜索框中搜索文件夹名称来访问该文件夹。(请注意,不保证远程文件夹布局在各个版本之间保持向后兼容)。