cordova-plugin-file

Android Testsuite Chrome Testsuite iOS Testsuite Lint Test

這個外掛程式實作了一個檔案 API,允許讀取/寫入裝置上的檔案。

這個外掛程式基於數個規格,包括:HTML5 檔案 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 規格已針對網頁瀏覽器棄用,但在 Cordova 應用程式中,此外掛程式支援「支援平台」列表中列出的平台上的 FileSystem API,但不包括瀏覽器平台。

若要了解如何使用此外掛程式的一些想法,請查看本頁底部的範例。如需其他範例(以瀏覽器為重點),請參閱 HTML5 Rocks 的FileSystem 文章

如需其他儲存選項的概觀,請參閱 Cordova 的儲存指南

這個外掛程式定義了一個全域 cordova.file 物件。

雖然該物件位於全域範圍內,但在觸發 deviceready 事件後,應用程式才能使用它。

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

安裝

cordova plugin add cordova-plugin-file

支援平台

  • Android
  • iOS
  • OS X
  • 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? 持續性? 作業系統清除 同步 私有
/var/mobile/Applications/<UUID>/ applicationStorageDirectory - r 不適用 不適用 不適用
   appname.app/ applicationDirectory 套件 r 不適用 不適用 不適用
      www/ - - r 不適用 不適用 不適用
   Documents/ documentsDirectory documents r/w
      NoCloud/ - documents-nosync r/w
   Library - library r/w 是?
      NoCloud/ dataDirectory library-nosync r/w
      Cloud/ syncedDataDirectory - r/w
      Caches/ cacheDirectory 快取 r/w 是* 是***
   tmp/ tempDirectory - r/w 否** 是***

* 檔案會在應用程式重新啟動和升級之間持續存在,但作業系統可以隨時清除此目錄。您的應用程式應該能夠重新建立任何可能被刪除的內容。

** 檔案可能會在應用程式重新啟動之間持續存在,但不要依賴此行為。無法保證檔案會在更新之間持續存在。您的應用程式應在適用時從這個目錄中移除檔案,因為作業系統不保證何時 (甚至是否) 移除這些檔案。

*** 作業系統可能會在認為必要時清除此目錄的內容,但不要依賴這一點。您應根據應用程式的需要清除此目錄。

Android 檔案系統配置

裝置路徑 cordova.file.* AndroidExtraFileSystems r/w? 持續性? 作業系統清除 私有
file:///android_asset/ applicationDirectory assets r 不適用 不適用
/data/data/<app-id>/ applicationStorageDirectory - r/w 不適用 不適用
   快取 cacheDirectory 快取 r/w 是*
   files dataDirectory files r/w
      Documents   documents r/w
<sdcard>/ externalRootDirectory sdcard r/w***
   Android/data/<app-id>/ externalApplicationStorageDirectory - r/w
      快取 externalCacheDirectory 快取-外部 r/w 否**
      files externalDataDirectory 檔案-外部 r/w

* 作業系統可能會定期清除此目錄,但不要依賴此行為。請根據應用程式的需要清除此目錄的內容。如果使用者手動清除快取,則會移除此目錄的內容。

** 作業系統不會自動清除此目錄;您有責任自行管理內容。如果使用者手動清除快取,則會移除此目錄的內容。

*** 從 API 30 開始,這些目錄不再可寫入。

注意:如果無法掛載外部儲存空間,cordova.file.external* 屬性會是 null

Android 的外部儲存空間注意事項

隨著範圍儲存空間的推出,透過檔案 API 存取外部儲存空間變得不可靠或受到限制。範圍儲存空間是在 API 29 中引入的。雖然現有的應用程式可能可以選擇退出,但這個選項不適用於新的應用程式。在 Android API 30 和更新版本上,範圍儲存空間會完全強制執行。

此外,API 29 不支援直接檔案存取。這表示此外掛程式無法在 API 29 裝置上存取外部儲存媒體。

API 30 引入了 FUSE,它允許使用檔案 API 對外部儲存空間進行有限的存取,讓此外掛程式可以再次部分運作。

有限存取包括但不限於

  • 具有適當的 READ_EXTERNALREAD_MEDIA_* 權限的唯讀存取。
  • 唯讀存取僅限於媒體檔案,但不包括文件。
  • 寫入僅限於您應用程式擁有的檔案。無法透過檔案 API 修改第三方應用程式擁有的檔案 (包括透過相機外掛程式建立的影像檔案)。
  • 並非外部儲存空間中的所有路徑都可寫入。

這些限制僅適用於外部檔案系統 (例如 cordova.file.external* 路徑)。不受這些限制的內部檔案系統,例如 cordova.file.dataDirectory 路徑。

如果與外部檔案系統互動是應用程式的需求,請考慮改用 MediaStore 外掛程式。

OS X 檔案系統配置

裝置路徑 cordova.file.* iosExtraFileSystems r/w? 作業系統清除 私有
/Applications/<appname>.app/ - 套件 r 不適用
    內容/資源/ applicationDirectory - r 不適用
~/Library/Application Support/<bundle-id>/ applicationStorageDirectory - r/w
    檔案/ dataDirectory - r/w
~/Documents/ documentsDirectory documents r/w
~/Library/Caches/<bundle-id>/ cacheDirectory 快取 r/w
/tmp/ tempDirectory - r/w 是*
/ rootDirectory r/w 否**

注意:這是非沙箱應用程式的配置。如果您啟用沙箱,applicationStorageDirectory 會在 ` ~/Library/Containers//Data/Library/Application Support` 下方。

* 檔案會在應用程式重新啟動和升級之間持續存在,但作業系統可以隨時清除此目錄。您的應用程式應該能夠重新建立任何可能被刪除的內容。您應根據應用程式的需要清除此目錄。

** 允許存取整個檔案系統。這僅適用於非沙箱應用程式。

Windows 檔案系統配置

裝置路徑 cordova.file.* r/w? 持續性? 作業系統清除 私有
ms-appdata:/// applicationDirectory r 不適用 不適用
   local/ dataDirectory r/w
   temp/ cacheDirectory r/w 是*
   temp/ tempDirectory r/w 是*
   roaming/ syncedDataDirectory r/w

* 作業系統可能會定期清除此目錄

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」將表示升級應用程式的現有使用者可能無法存取他們先前儲存的檔案,具體取決於他們的裝置。

如果您的應用程式是新的,或先前從未將檔案儲存在永久檔案系統中,則通常建議使用 Internal 設定。

對 /android_asset 的慢速遞迴操作

在 Android 上列出資源目錄非常慢。您可以透過將 src/android/build-extras.gradle 新增到您的 Android 專案根目錄(也需要 cordova-android@4.0.0 或更高版本)來加速此過程。

在 Marshmallow 上,外部儲存裝置未掛載時,寫入外部儲存裝置的權限

Marshmallow 要求應用程式在讀取/寫入外部位置時請求權限。根據預設,您的應用程式有權寫入 cordova.file.applicationStorageDirectorycordova.file.externalApplicationStorageDirectory,而且除非外部儲存裝置未掛載,否則插件不會請求這兩個目錄的權限。然而,由於限制,當外部儲存裝置未掛載時,它會要求寫入 cordova.file.externalApplicationStorageDirectory 的權限。

SDK 目標低於 29

根據官方的 Android 11 中的儲存空間更新文件,WRITE_EXTERNAL_STORAGE 權限已不再運作,且不提供存取權。

如果此權限未列入目標為 Build.VERSION_CODES.Q (SDK 29) 之前 API 等級的應用程式的允許清單中,則無法將此權限授予應用程式。

如果您需要新增此權限,請將以下內容新增至您的 config.xml

<config-file target="AndroidManifest.xml" parent="/*" xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
</config-file>

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 之前)交付給使用者,並且已將檔案儲存在永久檔案系統中,則您應該將偏好設定為 Compatibility。將位置切換到 Library 將表示升級應用程式的現有使用者將無法存取他們先前儲存的檔案。

如果您的應用程式是新的,或先前從未將檔案儲存在永久檔案系統中,則通常建議使用 Library 設定。

瀏覽器特性

常見的特性和注意事項

  • 每個瀏覽器都使用自己的沙箱檔案系統。IE 和 Firefox 使用 IndexedDB 作為基礎。所有瀏覽器在路徑中都使用正斜線作為目錄分隔符號。
  • 目錄條目必須依序建立。例如,如果 dir1 不存在,則呼叫 fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback) 將會失敗。
  • 插件會在應用程式首次啟動時請求使用者允許使用永久儲存空間。
  • 插件僅支援 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 TEMPORARYPERSISTENT 檔案系統配額沒有限制。
  • 若要增加 Chrome 中的永久儲存空間,您需要呼叫 window.initPersistentFileSystem 方法。預設情況下,永久儲存空間配額為 5 MB。
  • Chrome 需要 --allow-file-access-from-files 執行引數才能透過 file:/// 通訊協定支援 API。
  • 如果您在取得現有的 Entry 時使用旗標 {create:true},則 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)。
  • 在嘗試 moveTo 不存在的目錄時,會擲回 INVALID_MODIFICATION_ERR(代碼:9),而不是 NOT_FOUND_ERR(代碼:1)。

基於 IndexedDB 的實作特性(Firefox 和 IE)

  • 不支援 ...
  • IE 不支援 file:/// 模式;僅支援託管模式 (https://127.0.0.1:xxxx)。
  • Firefox 檔案系統大小沒有限制,但每個 50MB 擴充功能都會要求使用者允許。IE10 允許在不提示的情況下,實作檔案系統時最多使用 10mb 的合併 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 檔案系統的根目錄。因此,上述路徑現在都會以 fullPath

/path/to/file

FileEntry 物件表示。如果您的應用程式使用裝置絕對路徑,且您先前透過 Entry 物件的 fullPath 屬性擷取這些路徑,則您應該更新程式碼以改用 entry.toURL()

為了向後相容性,resolveLocalFileSystemURL() 方法會接受裝置絕對路徑,並且會傳回對應於該路徑的 Entry 物件,只要該檔案存在於 TEMPORARYPERSISTENT 檔案系統中即可。

這在使用 File-Transfer 插件時尤其是一個問題,該插件先前使用裝置絕對路徑(且仍然可以接受這些路徑)。它已更新為可以正確使用檔案系統 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

,可用於唯一識別檔案。

在 v7.0.0 版本中,Android 的 toURL() 回傳值已更新,當應用程式內容從 file:// 協定提供時,會回傳絕對 file:// URL。

如果應用程式內容從 http(s):// 協定提供,則會回傳 cdvfile 格式的 URL。cdvfile 格式的 URL 是從內部方法 toInternalURL() 建立的。

toInternalURL() 回傳檔案系統 URL 的範例

https://127.0.0.1/persistent/path/to/file

toURL flow

建議始終使用 toURL() 以確保回傳正確的 URL。

cdvfile 協定

  • Android 上不支援

目的

cdvfile://127.0.0.1/persistent|temporary|another-fs-root*/path/to/file 可用於平台獨立的檔案路徑。核心外掛程式支援 cdvfile 路徑 - 例如,您可以使用 cordova-plugin-file-transfer 將 mp3 檔案下載到 cdvfile 路徑,並使用 cordova-plugin-media 播放它。

*注意:關於可用的檔案系統根目錄的更多詳細資訊,請參閱檔案儲存位置檔案系統佈局外掛程式設定

若要將 cdvfile 用作標籤的 src,您可以透過已解析的 fileEntry 的 toURL() 方法將其轉換為原生路徑,您可以使用 resolveLocalFileSystemURL 取得 fileEntry - 請參閱以下範例。

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

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

注意:此方法需要更新以下內容安全規則

  • cdvfile: 協定新增到索引頁面的 Content-Security-Policy meta 標籤,例如:
    • <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 卡,則為 SD 卡的根目錄)。您必須具有 android.permission.WRITE_EXTERNAL_STORAGE 權限才能使用此目錄。
  • cache:應用程式的內部快取目錄
  • cache-external:應用程式的外部快取目錄
  • assets:應用程式的套件(唯讀)
  • root:整個裝置的檔案系統
  • applicationDirectory:具有受限存取的唯讀目錄。複製此目錄中的檔案是可行的,但直接讀取它會導致「找不到檔案」。Android 也支援名為「documents」的特殊檔案系統,它代表「files」檔案系統中的「/Documents/」子目錄。

iOS

  • library:應用程式的 Library 目錄
  • documents:應用程式的 Documents 目錄
  • cache:應用程式的 Cache 目錄
  • bundle:應用程式的套件;應用程式本身在磁碟上的位置(唯讀)
  • root:整個裝置的檔案系統

預設情況下,Library 和 Documents 目錄可以同步到 iCloud。您還可以請求兩個額外的檔案系統,library-nosyncdocuments-nosync,它們代表 /Library/Documents 檔案系統中特殊的非同步目錄。

範例:建立檔案和目錄、寫入、讀取和附加檔案

File 外掛程式可讓您執行諸如將檔案儲存在應用程式的暫時或持久儲存位置(沙箱儲存)以及將檔案儲存在其他平台相關位置等操作。本節中的程式碼片段示範不同的任務,包括:

建立持久檔案

在使用 File 外掛程式 API 之前,您可以使用 requestFileSystem 存取檔案系統。執行此操作時,您可以請求持久或暫時儲存。除非使用者授予權限,否則不會移除持久儲存。

當您使用 requestFileSystem 取得檔案系統存取權時,僅會授予對沙箱檔案系統的存取權(沙箱會限制對應用程式本身的存取),而不是對裝置上任何檔案系統位置的一般存取權。(若要存取沙箱儲存外部的檔案系統位置,請使用其他方法,例如 window.resolveLocalFileSystemURL,這些方法支援平台相關位置。有關範例,請參閱附加檔案。)

以下是對持久儲存的要求。

注意 當以 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 的 file 屬性來取得檔案參考,然後建立新的 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 的 write 方法。

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.dev.org.tw/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.dev.org.tw 新增到 index.html 中的 Content-Security-Policy元素中。

取得檔案後,將內容複製到新檔案。目前的 DirectoryEntry 物件已與應用程式快取相關聯。

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);
}

在建立子資料夾時,您需要如先前程式碼所示,分別建立每個資料夾。