cordova-plugin-file 4.3.0

cordova-plugin-file 4.3.0

测试已测试
语言语言 Obj-CObjective C
许可证 Apache 2
发布最后发布2016年11月

Holly Schinsky, Shazron Abdullah 维护。



  • Adobe PhoneGap 团队

标题:文件

描述:在设备上读写文件。

Android iOS Windows 8.1 Store Windows 8.1 Phone Windows 10 Store Travis CI
Build Status Build Status Build Status Build Status Build Status

cordova-plugin-file

此插件实现了一个 File API,允许对设备上驻留的文件进行读写访问。

此插件基于几个规范,包括:HTML5 File API http://www.w3.org/TR/FileAPI/

目录和系统扩展的最新版本:http://www.w3.org/TR/2012/WD-file-system-api-20120417/ 尽管此插件的大部分代码是在较早的规范现行时编写的:http://www.w3.org/TR/2011/WD-file-system-api-20110419/

它还实现了 FileWriter 规范:http://dev.w3.org/2009/dap/file-system/file-writer.html

注意 虽然 W3C FileSystem 规范已弃用于浏览器,但该 FileSystem API 在本插件支持的平台上(支持平台列表中列出,浏览器平台除外)支持 Cordova 应用。

要了解如何使用该插件的一些建议,请查看页面底部的 示例。有关更多示例(以浏览器为中心),请参阅 HTML5 Rocks 的 FileSystem 文章

有关其他存储选项的概述,请参阅 Cordova 的 存储指南

此插件定义了全局的 cordova.file 对象。

尽管在全局范围内,但在 deviceready 事件之后才能使用。

document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log(cordova.file);
}

Apache Cordova 问题跟踪器 上报告问题

安装

cordova plugin add cordova-plugin-file

支持的平台

  • Amazon Fire OS
  • Android
  • BlackBerry 10
  • Firefox OS
  • iOS
  • OS X
  • Windows Phone 7 和 8*
  • Windows 8*
  • Windows*
  • 浏览器

* 这些平台不支持 FileReader.readAsArrayBufferFileWriter.write(blob).

文件存储位置

截至v1.2.0版本,提供了重要文件系统目录的URL。每个URL的格式为file:///path/to/spot/,可以使用window.resolveLocalFileSystemURL()将其转换为DirectoryEntry

  • cordova.file.applicationDirectory - 应用程序安装的只读目录。(iOSAndroidBlackBerry 10OSXwindows

  • cordova.file.applicationStorageDirectory - 应用程序沙箱的根目录;在iOS和windows上,此位置为只读(但某些子目录,如iOS上的/Documents或在windows上的/localState,是读写)。沙箱内的所有数据都仅对应用程序私有。(iOSAndroidBlackBerry 10OSX

  • cordova.file.dataDirectory - 应用程序沙箱内部使用内部内存的持久私有数据存储(在Android上,如果您需要使用外部内存,请使用.externalDataDirectory)。在iOS上,此目录不与iCloud同步(请使用.syncedDataDirectory)。(iOSAndroidBlackBerry 10windows

  • cordova.file.cacheDirectory - 用于缓存的本地数据文件或任何您可以轻松重新创建的文件的目录。当设备存储空间不足时,操作系统可能会删除这些文件,但应用程序不应依赖操作系统删除这些文件。(iOSAndroidBlackBerry 10OSXwindows

  • cordova.file.externalApplicationStorageDirectory - 外部存储中的应用程序空间。(Android

  • cordova.file.externalDataDirectory - 外部存储中应用特定数据文件的位置。(Android

  • cordova.file.externalCacheDirectory - 外部存储中的应用程序缓存。(Android

  • cordova.file.externalRootDirectory - 外部存储(SD卡)的根目录。(AndroidBlackBerry 10

  • cordova.file.tempDirectory - 操作系统可以随时清理的临时目录。请勿依赖操作系统清理此目录;您的应用程序应始终根据适用性删除文件。(iOSOSXwindows

  • cordova.file.syncedDataDirectory - 包含应同步的应用特定文件(例如,到iCloud)。(iOSwindows

  • cordova.file.documentsDirectory - 仅对应用程序私有但对其他应用程序有意义的文件(例如,Office文件)。请注意,对于OSX,这是用户的~/Documents目录。(iOSOSX

  • cordova.file.sharedDirectory - 可供所有应用程序全局访问的文件。(BlackBerry 10

文件系统布局

虽然技术上是一个实现细节,但了解cordova.file.*属性如何映射到真实设备上的物理路径非常有用。

iOS文件系统布局

设备路径 cordova.file.* iosExtraFileSystems r/w? persistent? OS清除 同步 私有
/var/mobile/Applications/<UUID>/ applicationStorageDirectory - r N/A N/A N/A Yes
   appname.app/ applicationDirectory bundle r N/A N/A N/A Yes
      www/ - - r N/A N/A N/A Yes
   Documents/ documentsDirectory documents r/w Yes No Yes Yes
      NoCloud/ - documents-nosync r/w Yes No No Yes
   Library - library r/w Yes No Yes? Yes
      NoCloud/ dataDirectory library-nosync r/w Yes No No Yes
      Cloud/ syncedDataDirectory - r/w Yes No Yes Yes
      Caches/ cacheDirectory cache r/w Yes* Yes*** No Yes
   tmp/ tempDirectory - r/w No** Yes*** No Yes

* 文件可以在应用程序重启和升级之间持续存在,但此目录可以在操作系统想要的时候清除。您的应用程序应能够重新创建任何可能被删除的内容。

** 文件可能在应用程序重启之间持续存在,但请不要依赖此行为。文件在更新之间不一定保证持续存在。当它适用时,您的应用程序应从此目录中删除文件,因为操作系统不保证何时(甚至是否)删除这些文件。

***操作系统可能随时清除此目录的内容,但请不要依赖这一行为。您应该根据您的应用程序需求适当清除此目录。

Android 文件系统布局

设备路径 cordova.file.* AndroidExtraFileSystems r/w? persistent? OS清除 私有
file:///android_asset/ applicationDirectory assets r N/A N/A Yes
/data/data/<app-id>/ applicationStorageDirectory - r/w N/A N/A Yes
   cache cacheDirectory cache r/w Yes Yes* Yes
   files dataDirectory files r/w Yes No Yes
      Documents documents r/w Yes No Yes
<sdcard>/ externalRootDirectory sdcard r/w Yes No No
   Android/data/<app-id>/ externalApplicationStorageDirectory - r/w Yes No No
      cache externalCacheDirectry cache-external r/w Yes No** No
      files externalDataDirectory files-external r/w Yes No No

**操作系统可能会定期清除此目录,但请不要依赖这一行为。请根据您的应用程序适当的清除此目录内容。如果用户手动清除缓存,则此目录的内容将被删除。

***操作系统不会自动清除此目录;您需要自己管理内容。如果用户手动清除缓存,则目录内容将被移除。

注意:如果外部存储不可挂载,则 cordova.file.external* 属性将为 null

BlackBerry 10 文件系统布局

设备路径 cordova.file.* r/w? persistent? OS清除 私有
file:///accounts/1000/appdata/<app id>/ applicationStorageDirectory r N/A N/A Yes
   app/native applicationDirectory r N/A N/A Yes
   data/webviews/webfs/temporary/local__0 cacheDirectory r/w No Yes Yes
   data/webviews/webfs/persistent/local__0 dataDirectory r/w Yes No Yes
file:///accounts/1000/removable/sdcard externalRemovableDirectory r/w Yes No No
file:///accounts/1000/shared sharedDirectory r/w Yes No No

注意:当应用程序部署到工作范围时,所有路径相对于 /accounts/1000-enterprise。

OS X 文件系统布局

设备路径 cordova.file.* iosExtraFileSystems r/w? OS清除 私有
/Applications/<appname>.app/ - bundle r N/A Yes
    Content/Resources/ applicationDirectory - r N/A Yes
~/Library/Application Support/<bundle-id>/ applicationStorageDirectory - r/w No Yes
    files/ dataDirectory - r/w No Yes
~/Documents/ documentsDirectory documents r/w No No
~/Library/Caches/<bundle-id>/ cacheDirectory cache r/w No Yes
/tmp/ tempDirectory - r/w Yes* Yes
/ rootDirectory root r/w No** No

注意:这是非沙盒应用程序的布局。如果您启用沙盒,则 applicationStorageDirectory 将位于 ~/Library/Containers/<bundle-id>/Data/Library/Application Support 之下。

**文件将跨应用程序的重启和升级持续存在,但操作系统可以在任何时候清除此目录。您的应用程序应该能够重新创建可能被删除的任何内容。您应该根据您的应用程序需求适当的清除此目录。

**允许访问整个文件系统。这仅适用于非沙盒应用程序。

Windows 文件系统布局

设备路径 cordova.file.* r/w? persistent? OS清除 私有
ms-appdata:/// applicationDirectory r N/A N/A Yes
   local/ dataDirectory r/w Yes No Yes
   temp/ cacheDirectory r/w No Yes* Yes
   temp/ tempDirectory r/w No Yes* Yes
   roaming/ syncedDataDirectory r/w Yes No Yes

**操作系统可能会定期清除此目录。

Android 特性

Android 持久存储位置

在 Android 设备上存储持久文件的多个有效位置。有关各种可能性的详细讨论,请参阅此页面

插件先前的版本会在启动时根据设备是否声明 SD 卡(或等效存储分区)已挂载来选择临时和持久文件的位置。如果 SD 卡已挂载,或者有一个大的内部存储分区可用(例如 Nexus 设备上),则持久文件将存储在该空间的根目录下。这意味着所有 Cordova 应用都可以看到该卡上的所有文件。

如果SD卡不可用,则旧版本会在 /data/data/<packageId> 下存储数据,这样可以使应用程序相互隔离,但仍可能导致数据之间共享。

现在可以在您的应用程序的 config.xml 文件中选择是否要在内部文件存储位置存储文件,或者使用旧的逻辑。为此,请将以下其中一行添加到 config.xml

<preference name="AndroidPersistentFileLocation" value="Internal" />

<preference name="AndroidPersistentFileLocation" value="Compatibility" />

如果没有这行代码,File插件将使用 Internal 作为默认设置。如果存在偏好标签,并且不是这些值之一,则应用程序将无法启动。

如果您的应用程序之前已经发行给用户,并使用此插件的旧版本(3.0.0之前),并在持久文件系统中存储了文件,那么如果您在 config.xml 中没有指定持久文件系统的位置,则应将首选项设置为 Compatibility。将位置切换到“内部”意味着升级应用程序的现有用户可能会无法访问他们之前存储的文件,这取决于他们的设备。

如果您的应用程序是新的,或者从未在持久文件系统中存储文件,那么通常建议使用 Internal 设置。

Android_asset 的慢速递归操作

在Android上,列出资源目录非常慢。您可以通过将 src/android/build-extras.gradle 添加到 Android 项目的根目录中(也要求Android版本 4.4 或更高)来加速这个过程。

在马什莫兰(Marshmallow)未挂载时写入外部存储的权限

Marshmallow 要求应用程序在读取/写入外部位置时请求权限。默认情况下,您的应用程序有权限写入 cordova.file.applicationStorageDirectorycordova.file.externalApplicationStorageDirectory,并且插件不会请求这两个目录的权限,除非外部存储未挂载。但是,由于一个限制,当外部存储未挂载时,它将请求写入 cordova.file.externalApplicationStorageDirectory 的权限。

关于iOS的怪癖

  • cordova.file.applicationStorageDirectory 是只读的;试图在根目录中存储文件将失败。请使用为iOS定义的其他 cordova.file.* 属性之一(只有 applicationDirectoryapplicationStorageDirectory 是只读的)。
  • FileReader.readAsText(blob, encoding)
    • 不支持 encoding 参数,总是使用 UTF-8 编码。

iOS 持久存储位置

在iOS设备上存储持久文件的有效位置有两个:Documents 文件夹和Library 文件夹。此插件的前几版始终在Documents 文件夹中存储持久文件,这让所有应用程序文件都可通过iTunes访问,这通常是意外的,尤其是对于处理大量小文件而不是生成完整文档以导出的应用程序,而这是目录的预期用途。

现在可以在您的应用程序的 config.xml 文件中设置首选项,以便选择是否将文件存储在文档目录或库目录中。为此,请将以下其中一行添加到 config.xml

<preference name="iosPersistentFileLocation" value="Library" />

<preference name="iosPersistentFileLocation" value="Compatibility" />

如果没有这行代码,File插件将使用 Compatibility 作为默认设置。如果存在偏好标签,并且不是这些值之一,则应用程序将无法启动。

如果您的应用程序之前已向用户发布,并使用本插件的旧版本(1.0之前)进行了发布,并且在持久文件系统中存储了文件,那么您应该将首选项设置为兼容性。将位置切换到将意味着升级应用程序的现有用户将无法访问其之前存储的文件。

如果您的应用程序是新的,或者以前从未在持久文件系统中存储文件,那么通常建议使用设置。

Firefox OS 特性

Firefox OS 不原生支持文件系统API,而是作为indexedDB之上的适配层实现的。

  • 删除非空目录时不会失败
  • 不支持目录的元数据
  • 方法copyTomoveTo不支持目录

以下数据路径得到支持

  • applicationDirectory - 使用xhr获取与应用程序打包的本地文件。
  • dataDirectory - 用于持久应用程序特定数据文件。
  • cacheDirectory - 应该在应用程序重启后继续存在的缓存文件(应用程序不应依赖于操作系统在此处删除文件)。

浏览器特性

常见特性及备注

  • 每个浏览器都使用自己的沙盒文件系统。IE和Firefox使用IndexedDB作为基础。所有浏览器都使用斜线作为路径分隔符。
  • 必须连续创建目录条目。例如,如果调用fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback)时dir1不存在,该调用将失败。
  • 插件在应用程序首次启动时请求用户权限以使用持久存储。
  • 插件只支持cdvfile://127.0.0.1(本地资源)。也就是说,不能通过cdvfile访问外部资源。
  • 插件不支持“文件系统API 8.3 命名限制”
  • Blob和File的close函数不受支持。
  • FileSaverBlobBuilder不受此插件支持,也没有提供占位程序。
  • 插件不支持requestAllFileSystems。这个函数也在规范中缺失。
  • 如果您使用create: true标志为现有目录创建条目,目录条目不会被删除。
  • 通过构造函数创建的文件不受支持。您应该使用entry.file方法。
  • 每个浏览器都使用自己的blob URL引用形式。
  • 支持readAsDataURL函数,但是Chrome中的媒体类型取决于条目名的扩展名,IE中的媒体类型始终为空(根据规范,与text-plain相同),Firefox中的媒体类型始终为application/octet-stream。例如,如果内容是abcdefg,那么Firefox返回data:application/octet-stream;base64,YWJjZGVmZw==,IE返回data:;base64,YWJjZGVmZw==,Chrome返回data:;;base64,YWJjZGVmZw==
  • toInternalURL返回的路径形式为file:///persistent/path/to/entry(Firefox,IE)。Chrome返回的路径形式为cdvfile://127.0.0.1/persistent/file

Chrome 特性

  • Chrome文件系统在设备就绪事件后不会立即准备好。作为一种替代方案,您可以订阅filePluginIsReady事件。示例:
window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false);

您可以使用window.isFilePluginReadyRaised函数检查事件是否已经触发。

  • Chrome中没有限制window.requestFileSystem TEMPORARY和PERSISTENT文件系统配额。
  • 要增加Chrome的持久存储,需要调用window.initPersistentFileSystem方法。默认的持久存储配额为5MB。
  • Chrome需要--allow-file-access-from-files运行参数来支持file:///协议下的API。
  • 如果在使用标志{create:true}获取现有Entry时,不修改File对象。
  • Chrome中,事件cancelable属性设置为true,这与规范相反。
  • Chrome中的toURL函数根据应用程序的主机返回以filesystem:开头的路径。例如,filesystem:file:///persistent/somefile.txtfilesystem:https://127.0.0.1:8080/persistent/somefile.txt
  • 在目录条目的情况下,toURL的结果不包含尾部斜杠。尽管如此,Chrome可以正确地解析带有尾部斜杠的URL。
  • resolveLocalFileSystemURL方法要求传入的url具有filesystem前缀。例如,resolveLocalFileSystemURLurl参数应采用格式filesystem:file:///persistent/somefile.txt,而不是Android中的格式file:///persistent/somefile.txt
  • 已弃用的toNativeURL函数不受支持且没有占位符。
  • setMetadata函数在规范中没有说明,也不受支持。
  • 在请求不存在的文件系统时,会抛出INVALID_MODIFICATION_ERR(代码:9),而不是SYNTAX_ERR(代码:8)。
  • 在尝试独占创建已存在的文件或目录时,会抛出INVALID_MODIFICATION_ERR(代码:9),而不是PATH_EXISTS_ERR(代码:12)。
  • 在尝试在根文件系统上调用removeRecursively时,会抛出INVALID_MODIFICATION_ERR(代码:9),而不是NO_MODIFICATION_ALLOWED_ERR(代码:6)。
  • 在尝试移动不存在目录时,会抛出INVALID_MODIFICATION_ERR(代码:9),而不是NOT_FOUND_ERR(代码:1)。

基于IndexedDB的实现上的特殊性(Firefox和IE)

  • ...不受支持。
  • IE不支持file:///模式;仅支持托管模式(例如,https://127.0.0.1:xxxx)。
  • Firefox文件系统大小没有限制,但每个50MB扩展都会请求用户权限。IE10允许在不提示的情况下在文件系统中使用最多10MB的combined AppCache和IndexedDB,一旦达到该水平,就会询问是否希望将其增加至每个站点最多250MB。因此,requestFileSystem函数的size参数不会影响Firefox和IE中的文件系统。
  • readAsBinaryString函数在规范中没有说明,在IE中不受支持且没有占位符。
  • file.type始终为null。
  • 不应该使用已删除的DirectoryEntry实例回调结果创建条目。否则,会得到一个“悬挂条目”。
  • 在读取新写入的文件之前,需要获取该文件的新实例。
  • setMetadata函数在规范中没有说明,但只支持modificationTime字段的变化。
  • copyTomoveTo函数不支持目录。
  • 不支持目录元数据。
  • Entry.remove和directoryEntry.removeRecursively在删除非空目录时不会失败——被删除的目录及其内容将一起清理。
  • 不支持aborttruncate函数。
  • 不会触发进度事件。例如,此处理程序将不会执行
writer.onprogress = function() { /*commands*/ };

升级说明

在此插件v1.0.0中,FileEntryDirectoryEntry结构已经改变,以更符合发布的规范。

该插件之前的(1.0.0之前的)版本在Entry对象的fullPath属性中存储了设备绝对文件位置。这些路径通常看起来像

/var/mobile/Applications/<application UUID>/Documents/path/to/file  (iOS)
/storage/emulated/0/path/to/file                                    (Android)

这些路径也由Entry对象的toURL()方法返回。

在v1.0.0版中,fullPath属性是文件的路径,相对于HTML文件系统的根目录。因此,上述路径现在都将由带有fullPathFileEntry对象表示

/path/to/file

如果您的应用程序使用设备绝对路径,并且您之前通过Entry对象的fullPath属性检索了这些路径,那么您应该更新代码以使用entry.toURL()

为了向后兼容,resolveLocalFileSystemURL()方法将接受一个设备绝对路径,并且只要该文件存在于TEMPORARYPERSISTENT文件系统中,它将返回相对应的Entry对象。

这尤其是一个问题,File-Transfer插件之前使用设备绝对路径(并且仍然可以接受它们),现在已更新为正确处理FileSystem URL,所以将entry.fullPath替换为entry.toURL()应该解决该插件与设备上的文件一起使用时出现的问题。

在v1.1.0中,toURL()的返回值已更改(见CB-6394),尽可能返回一个绝对'file://' URL。为了确保一个'cdvfile:'-URL,现在可以使用toInternalURL()。此方法现在将返回以下形式的文件系统URL

cdvfile://127.0.0.1/persistent/path/to/file

这可以用来唯一地识别文件。

cdvfile协议

目的

cdvfile://127.0.0.1/persistent|temporary|another-fs-root*/path/to/file可以用作平台无关的文件路径。cdvfile路径由核心插件支持 - 例如,您可以通过cordova-plugin-file-transfer将mp3文件下载到cdvfile路径并使用cordova-plugin-media播放它。

注意:有关可用的fs根的更多详细信息,请参阅文件存储位置文件系统结构配置插件(可选)

要将cdvfile用作标签的src属性,您可以将它通过获取的fileEntry的toURL()方法转换为本地路径,您可以通过resolveLocalFileSystemURL获取该路径 - 下面有一些示例。

您还可以在DOM中直接使用cdvfile://路径,例如

<img src="cdvfile://127.0.0.1/persistent/img/logo.png" />

注意:此方法需要更新以下内容安全规则

  • cdvfile:方案添加到索引页面的Content-Security-Policy元标签中,例如
    • <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap:cdvfile:https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
  • <access origin="cdvfile://*" />添加到config.xml

将cdvfile://转换为本地路径

resolveLocalFileSystemURL('cdvfile://127.0.0.1/temporary/path/to/file.mp4', function(entry) {
    var nativePath = entry.toURL();
    console.log('Native URI: ' + nativePath);
    document.getElementById('video').src = nativePath;

将本地路径转换为cdvfile://

resolveLocalFileSystemURL(nativePath, function(entry) {
    console.log('cdvfile URI: ' + entry.toInternalURL());

在核心插件中使用cdvfile

fileTransfer.download(uri, 'cdvfile://127.0.0.1/temporary/path/to/file.mp3', function (entry) { ...
var my_media = new Media('cdvfile://127.0.0.1/temporary/path/to/file.mp3', ...);
my_media.play();

cdvfile怪癖

  • 在Windows平台上不支持在DOM中使用cdvfile://路径(路径可以转换为本地路径)。

错误代码及含义列表

当抛出错误时,以下代码之一将用于。

代码 常量
1 NOT_FOUND_ERR
2 SECURITY_ERR
3 ABORT_ERR
4 NOT_READABLE_ERR
5 ENCODING_ERR
6 NO_MODIFICATION_ALLOWED_ERR
7 INVALID_STATE_ERR
8 SYNTAX_ERR
9 INVALID_MODIFICATION_ERR
10 QUOTA_EXCEEDED_ERR
11 TYPE_MISMATCH_ERR
12 PATH_EXISTS_ERR

配置插件(可选)

可以按平台配置可用的文件系统集合。iOS和Android都识别config.xml中的一个标签,该标签命名要安装的文件系统。默认情况下,所有文件系统根目录均启用。

<preference name="iosExtraFilesystems" value="library,library-nosync,documents,documents-nosync,cache,bundle,root" />
<preference name="AndroidExtraFilesystems" value="files,files-external,documents,sdcard,cache,cache-external,assets,root" />

Android

  • files:应用程序的内部文件存储目录
  • files-external:应用程序的外部文件存储目录
  • sdcard:全局外部文件存储目录(这是SD卡的根目录,如果已安装)。您必须具有android.permission.WRITE_EXTERNAL_STORAGE权限才能使用此目录。
  • cache:应用程序的内部缓存目录
  • cache-external:应用程序的外部缓存目录
  • assets:应用程序的 bundles(只读)
  • root:整个设备的文件系统

Android还支持一个名为“documents”的特殊文件系统,它代表“files”文件系统中“/Documents/”子目录。

iOS

  • library:应用程序的 Library 目录
  • documents:应用程序的 Documents 目录
  • cache:应用程序的 Cache 目录
  • bundle:应用程序的 bundle;应用程序在磁盘上的位置(只读)
  • root:整个设备的文件系统

默认情况下,library 和 documents 目录可以同步到iCloud。您还可以请求另外两个文件系统,即library-nosyncdocuments-nosync,这两个文件系统代表一个特殊的非同步目录,位于/Library/Documents文件系统中。

示例:创建文件和目录,写、读和附加文件

文件插件允许您在应用程序中执行诸如将文件存储在临时或持久存储位置(沙箱存储)以及存储在平台相关位置的操作。本节中的代码示例演示了不同的任务,包括

创建持久文件

在您使用文件插件 API 之前,您可以使用 requestFileSystem 来获取对文件系统的访问权限。当这样做时,您可以请求持久或临时存储。持久存储除非用户授权,否则不会被删除。

当您使用 requestFileSystem 获取文件系统访问权限时,只授予对沙箱文件系统的访问权限(沙箱限制对应用程序自身的访问),而不是对设备的任何文件系统位置的通用访问。(要访问沙箱存储之外的其他文件系统位置,请使用其他方法,例如window.requestLocalFileSystemURL,它支持平台特定的位置。例如,请参阅“附加文件”)

以下是频繁使用持久存储的一个示例。

注意 当针对WebView客户端(而不是浏览器)或原生应用(Windows)时,在持久存储之前无需使用 requestQuota

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {

    console.log('file system open: ' + fs.name);
    fs.root.getFile("newPersistentFile.txt", { create: true, exclusive: false }, function (fileEntry) {

        console.log("fileEntry is file?" + fileEntry.isFile.toString());
        // fileEntry.name == 'someFile.txt'
        // fileEntry.fullPath == '/someFile.txt'
        writeFile(fileEntry, null);

    }, onErrorCreateFile);

}, onErrorLoadFs);

成功回调接收 FileSystem 对象(fs)。使用 fs.root 来返回一个 DirectoryEntry 对象,您可以使用它来创建或获取一个文件(通过调用 getFile)。在这个示例中,fs.root 是一个 DirectoryEntry 对象,代表沙箱文件系统中的持久存储。

getFile 的成功回调接收一个 FileEntry 对象。您可以使用它来执行文件读写操作。

创建临时文件

以下是请求临时存储的一个示例。如果设备内存不足,操作系统可能会删除临时存储。

window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {

    console.log('file system open: ' + fs.name);
    createFile(fs.root, "newTempFile.txt", false);

}, onErrorLoadFs);

当使用临时存储时,你可以通过调用 getFile 来创建或获取文件。正如持久化存储示例所示,这将为您提供一个 FileEntry 对象,您可以使用此对象进行读取或写入操作。

function createFile(dirEntry, fileName, isAppend) {
    // Creates a new file or returns the file if it already exists.
    dirEntry.getFile(fileName, {create: true, exclusive: false}, function(fileEntry) {

        writeFile(fileEntry, null, isAppend);

    }, onErrorCreateFile);

}

写入文件

一旦拥有 FileEntry 对象,您可以通过调用 createWriter 来向文件写入,这在成功回调中返回 FileWriter 对象。调用 FileWriter 的 write 方法来写入文件。

function writeFile(fileEntry, dataObj) {
    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file write...");
            readFile(fileEntry);
        };

        fileWriter.onerror = function (e) {
            console.log("Failed file write: " + e.toString());
        };

        // If data object is not passed in,
        // create a new Blob instead.
        if (!dataObj) {
            dataObj = new Blob(['some file data'], { type: 'text/plain' });
        }

        fileWriter.write(dataObj);
    });
}

读取文件

您还需要 FileEntry 对象来读取现有的文件。使用 FileEntry 的文件属性来获取文件引用,然后创建一个新的 FileReader 对象。您可以使用类似于 readAsText 的方法来开始读取操作。当读取操作完成时,this.result 存储读取操作的结果。

function readFile(fileEntry) {

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

        reader.onloadend = function() {
            console.log("Successful file read: " + this.result);
            displayFileData(fileEntry.fullPath + ": " + this.result);
        };

        reader.readAsText(file);

    }, onErrorReadFile);
}

使用其他方法追加文件

当然,您通常希望追加现有文件而不是创建新文件。这里有一个例子。此示例显示您可以使用 window.resolveLocalFileSystemURL 访问文件系统的一种另一种方式。在此示例中,将跨平台 Cordova 文件 URL, cordova.file.dataDirectory,传递给函数。成功回调接收一个 DirectoryEntry 对象,您可以使用它来创建文件等操作。

window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) {
    console.log('file system open: ' + dirEntry.name);
    var isAppend = true;
    createFile(dirEntry, "fileToAppend.txt", isAppend);
}, onErrorLoadFs);

除了此用法外,您还可以使用 resolveLocalFileSystemURL 来获取访问不属于沙盒存储系统的一些文件系统位置。有关更多信息,请参阅 文件存储位置;许多这些存储位置是特定于平台的。您也可以使用 cdvfile 协议 将跨平台文件系统位置传递给 resolveLocalFileSystemURL

对于追加操作,前述代码中调用的 createFile 函数(请参阅前述示例中的实际代码)中没有新增的内容。createFile 调用 writeFile。在 writeFile 中,您检查是否请求了追加操作。

一旦您有了 FileWriter 对象,调用 seek 方法,并传递您想要写入的位置的索引值。在此示例中,您还测试文件是否存在。调用 seek 后,然后调用 FileWriter 的写入方法。

function writeFile(fileEntry, dataObj, isAppend) {
    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file read...");
            readFile(fileEntry);
        };

        fileWriter.onerror = function (e) {
            console.log("Failed file read: " + e.toString());
        };

        // If we are appending data to file, go to the end of the file.
        if (isAppend) {
            try {
                fileWriter.seek(fileWriter.length);
            }
            catch (e) {
                console.log("file doesn't exist!");
            }
        }
        fileWriter.write(dataObj);
    });
}

存储现有二进制文件

我们已显示了如何写入沙盒文件系统中刚创建的文件。如果您需要获取对现有文件的访问权限并将其转换为可在设备上存储的内容怎么办?在此示例中,您使用 xhr 请求获取文件,然后将其保存到沙盒文件系统的缓存中。

在获取文件之前,使用 requestFileSystem 获取 FileSystem 引用。通过在方法调用中传递 window.TEMPORARY(与之前相同),返回的 FileSystem 对象(fs)代表沙盒文件系统的缓存。使用 fs.root 获取所需的 DirectoryEntry 对象。

window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {

    console.log('file system open: ' + fs.name);
    getSampleFile(fs.root);

}, onErrorLoadFs);

为了完整性,这里提供了获取 Blob 图像的 xhr 请求。此代码中没有 Cordova 特定内容,除了您将已获得的 DirectoryEntry 引用作为参数传递给 saveFile 函数。您将保存 blob 图像,在读取文件后(以验证操作)稍后显示此文件。

function getSampleFile(dirEntry) {

    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://cordova.net.cn/static/img/cordova_bot.png', true);
    xhr.responseType = 'blob';

    xhr.onload = function() {
        if (this.status == 200) {

            var blob = new Blob([this.response], { type: 'image/png' });
            saveFile(dirEntry, blob, "downloadedImage.png");
        }
    };
    xhr.send();
}

注意针对Cordova 5安全,前面的代码要求您将域名 https://cordova.net.cn 添加到index.html中的Content-Security-Policy元素。

获取文件后,将内容复制到一个新文件中。当前的DirectoryEntry对象已与app缓存关联。

function saveFile(dirEntry, fileData, fileName) {

    dirEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {

        writeFile(fileEntry, fileData);

    }, onErrorCreateFile);
}

在writeFile中,您将Blob对象传递给dataObj,并将它保存到新文件中。

function writeFile(fileEntry, dataObj, isAppend) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file write...");
            if (dataObj.type == "image/png") {
                readBinaryFile(fileEntry);
            }
            else {
                readFile(fileEntry);
            }
        };

        fileWriter.onerror = function(e) {
            console.log("Failed file write: " + e.toString());
        };

        fileWriter.write(dataObj);
    });
}

将内容写入文件后,读取并显示它。您已将图片保存为二进制数据,因此可以使用FileReader.readAsArrayBuffer读取它。

function readBinaryFile(fileEntry) {

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

        reader.onloadend = function() {

            console.log("Successful file write: " + this.result);
            displayFileData(fileEntry.fullPath + ": " + this.result);

            var blob = new Blob([new Uint8Array(this.result)], { type: "image/png" });
            displayImage(blob);
        };

        reader.readAsArrayBuffer(file);

    }, onErrorReadFile);
}

读取数据后,可以使用如下代码显示图片。使用window.URL.createObjectURL获取Blob图片的DOM字符串。

function displayImage(blob) {

    // Displays image if result is a valid DOM string for an image.
    var elem = document.getElementById('imageFile');
    // Note: Use window.URL.revokeObjectURL when finished with image.
    elem.src = window.URL.createObjectURL(blob);
}

显示图片文件

要使用FileEntry显示图片,您可以调用toURL方法。

function displayImageByFileURL(fileEntry) {
    var elem = document.getElementById('imageFile');
    elem.src = fileEntry.toURL();
}

如果您使用特定平台的URI而不是FileEntry来显示图片,您可能需要在index.html中的Content-Security-Policy元素中包含URI的主要部分。例如,在Windows 10上,您可以包括ms-appdata:。以下是示例。

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: ms-appdata: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">

创建目录

在此代码中,您在应用存储位置的根目录中创建目录。您可以用任何可写存储位置(即任何DirectoryEntry)使用此代码。在这里,您通过将fs.root传递给此函数来写入应用缓存(假设您使用了window.TEMPORARY获取FileSystem对象)。

此代码在应用缓存中创建了/NewDirInRoot/images文件夹。对于特定平台的值,请查看文件系统布局

function createDirectory(rootDirEntry) {
    rootDirEntry.getDirectory('NewDirInRoot', { create: true }, function (dirEntry) {
        dirEntry.getDirectory('images', { create: true }, function (subDirEntry) {

            createFile(subDirEntry, "fileInNewSubDir.txt");

        }, onErrorGetDir);
    }, onErrorGetDir);
}

创建子文件夹时,需要像前面代码中所示单独创建每个文件夹。