File System API

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

注意:此功能在 Web Workers 中可用。

檔案系統 API — 透過 檔案系統訪問 API 提供的擴充套件,允許訪問裝置檔案系統上的檔案 — 提供了讀取、寫入和檔案管理功能。

請參閱 與其他檔案相關 API 的關係,以瞭解此 API、檔案和目錄條目 API 以及 檔案 API 之間的比較。

概念與用法

此 API 允許與使用者本地裝置上的檔案或使用者可訪問的網路檔案系統進行互動。此 API 的核心功能包括讀取檔案、寫入或儲存檔案以及訪問目錄結構。

與檔案和目錄的大部分互動是透過控制代碼完成的。一個父級 FileSystemHandle 類有助於定義兩個子類:FileSystemFileHandleFileSystemDirectoryHandle,分別代表檔案和目錄。

控制代碼代表使用者系統上的檔案或目錄。您可以透過使用 window.showOpenFilePicker()window.showDirectoryPicker() 等方法向用戶顯示檔案或目錄選擇器來首先獲得對它們的訪問。一旦呼叫這些方法,檔案選擇器就會出現,使用者會選擇一個檔案或目錄。一旦成功發生,就會返回一個控制代碼。

您也可以透過以下方式獲得檔案控制代碼的訪問許可權:

每個控制代碼都提供其自身的功能,並且根據您使用的控制代碼,會有一些差異(有關具體細節,請參閱介面部分)。然後,您可以訪問檔案資料,或所選目錄的資訊(包括其子項)。此 API 打開了 Web 一直以來所缺乏的潛在功能。儘管如此,在設計 API 時,安全性一直是重中之重,除非使用者明確允許,否則不允許訪問檔案/目錄資料(但這不適用於 源私有檔案系統,因為它對使用者不可見)。

注意:在 spec 中定義的相應頁面上列出了使用此 API 功能時可能引發的不同異常。然而,API 與底層作業系統之間的互動使情況更加複雜。已提出一項 在 spec 中列出錯誤對映 的提案,其中包含有用的相關資訊。

注意:基於 FileSystemHandle 的物件也可以被序列化成 IndexedDB 資料庫例項,或者透過 postMessage() 傳輸。

源私有檔案系統

源私有檔案系統 (OPFS) 是作為檔案系統 API 的一部分提供的儲存端點,它對頁面的源是私有的,並且不像常規檔案系統那樣對使用者可見。它提供了對一種特殊型別檔案的訪問,該檔案針對性能進行了高度最佳化,並提供了對其內容的就地寫入訪問。

以下是一些可能的用例:

  • 具有持久上傳功能的應用程式

    • 當選擇一個檔案或目錄進行上傳時,您可以將檔案複製到本地沙箱中,然後分塊上傳。
    • 應用程式可以在中斷後重新啟動上傳,例如瀏覽器關閉或崩潰、連線中斷或計算機關機。
  • 影片遊戲或其他具有大量媒體資源的應用程式

    • 應用程式下載一個或多個大型 tar 包,並將它們本地解壓到目錄結構中。
    • 應用程式在後臺預取資源,以便使用者在不等待下載的情況下進行下一個任務或遊戲關卡。
  • 具有離線訪問或本地快取的音訊或照片編輯器(非常適合提高效能和速度)

    • 應用程式可以就地寫入檔案(例如,僅覆蓋 ID3/EXIF 標籤而不覆蓋整個檔案)。
  • 離線影片播放器

    • 應用程式可以下載大型檔案(>1GB)以供以後觀看。
    • 應用程式可以訪問部分下載的檔案(這樣您就可以觀看 DVD 的第一章,即使應用程式仍在下載其餘內容,或者即使應用程式未能完成下載,因為您不得不匆忙趕火車)。
  • 離線 Web 郵件客戶端

    • 客戶端下載附件並將其本地儲存。
    • 客戶端快取附件以供以後上傳。

請閱讀我們的 源私有檔案系統 以獲取如何使用它的說明。

儲存檔案

  • 對於非同步控制代碼,請使用 FileSystemWritableFileStream 介面。一旦您想要儲存的資料是 BlobString 物件、字串字面量或 buffer 的格式,您就可以開啟一個流並將資料儲存到檔案中。這可以是現有檔案或新檔案。
  • 對於同步 FileSystemSyncAccessHandle,您可以使用 write() 方法將更改寫入檔案。您還可以選擇呼叫 flush(),如果您需要在特定時間將更改提交到磁碟(否則,您可以讓底層作業系統自行處理,這在大多數情況下是可以的)。

介面

FileSystemChangeRecord 實驗性

包含由 FileSystemObserver 觀察到的單個更改的詳細資訊。

FileSystemHandle

表示檔案系統條目的物件。多個控制代碼可以表示同一個條目。在大多數情況下,您不直接處理 FileSystemHandle,而是處理其子介面 FileSystemFileHandleFileSystemDirectoryHandle

FileSystemFileHandle

提供對檔案系統條目的控制代碼。

FileSystemDirectoryHandle

提供對檔案系統目錄的控制代碼。

FileSystemObserver 實驗性

提供一種觀察選定檔案或目錄更改的機制。

FileSystemSyncAccessHandle

提供檔案系統條目的同步控制代碼,該控制代碼直接在磁碟上的單個檔案上進行操作。檔案讀寫的同步性使得在非同步操作具有高開銷的上下文中(例如 WebAssembly)關鍵方法具有更高的效能。此類僅在 源私有檔案系統 內的專用 Web Worker 中可訪問。

FileSystemWritableFileStream

一個 WritableStream 物件,具有額外的便捷方法,直接在磁碟上的單個檔案上操作。

其他介面的擴充套件

Window.showDirectoryPicker()

顯示一個目錄選擇器,允許使用者選擇一個目錄。

Window.showOpenFilePicker()

顯示一個檔案選擇器,允許使用者選擇一個或多個檔案。

Window.showSaveFilePicker()

顯示一個檔案選擇器,允許使用者儲存一個檔案。

DataTransferItem.getAsFileSystemHandle()

返回一個 Promise,如果拖動的項是檔案,則以 FileSystemFileHandle 解析;如果拖動的項是目錄,則以 FileSystemDirectoryHandle 解析。

StorageManager.getDirectory()

用於獲取對 FileSystemDirectoryHandle 物件的引用,允許訪問儲存在 源私有檔案系統 中的目錄及其內容。返回一個 Promise,該 Promise 以 FileSystemDirectoryHandle 物件解析。

示例

訪問檔案

下面的程式碼允許使用者從檔案選擇器中選擇一個檔案。

js
async function getFile() {
  // Open file picker and destructure the result the first handle
  const [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  return file;
}

以下非同步函式顯示一個檔案選擇器,一旦選擇了一個檔案,就會使用 getFile() 方法檢索內容。

js
const pickerOpts = {
  types: [
    {
      description: "Images",
      accept: {
        "image/*": [".png", ".gif", ".jpeg", ".jpg"],
      },
    },
  ],
  excludeAcceptAllOption: true,
  multiple: false,
};

async function getTheFile() {
  // Open file picker and destructure the result the first handle
  const [fileHandle] = await window.showOpenFilePicker(pickerOpts);

  // get file contents
  const fileData = await fileHandle.getFile();
}

訪問目錄

以下示例返回一個具有指定名稱的目錄控制代碼。如果目錄不存在,則會建立它。

js
const dirName = "directoryToGetName";

// assuming we have a directory handle: 'currentDirHandle'
const subDir = await currentDirHandle.getDirectoryHandle(dirName, {
  create: true,
});

以下非同步函式使用 resolve() 方法查詢相對於指定目錄控制代碼的選定檔案的路徑。

js
async function returnPathDirectories(directoryHandle) {
  // Get a file handle by showing a file picker:
  const [handle] = await self.showOpenFilePicker();
  if (!handle) {
    // User cancelled, or otherwise failed to open a file.
    return;
  }

  // Check if handle exists inside our directory handle
  const relativePaths = await directoryHandle.resolve(handle);

  if (relativePaths === null) {
    // Not inside directory handle
  } else {
    // relativePaths is an array of names, giving the relative path

    for (const name of relativePaths) {
      // log each entry
      console.log(name);
    }
  }
}

寫入檔案

以下非同步函式開啟儲存檔案選擇器,一旦選擇檔案,該選擇器將返回一個 FileSystemFileHandle。然後使用 FileSystemFileHandle.createWritable() 方法建立可寫流。

使用者定義的 Blob 然後被寫入流,隨後流被關閉。

js
async function saveFile() {
  // create a new handle
  const newHandle = await window.showSaveFilePicker();

  // create a FileSystemWritableFileStream to write to
  const writableStream = await newHandle.createWritable();

  // write our file
  await writableStream.write(imgBlob);

  // close the file and write the contents to disk.
  await writableStream.close();
}

以下顯示了可以傳遞到 write() 方法的選項的不同示例。

js
// just pass in the data (no options)
writableStream.write(data);

// writes the data to the stream from the determined position
writableStream.write({ type: "write", position, data });

// updates the current file cursor offset to the position specified
writableStream.write({ type: "seek", position });

// resizes the file to be size bytes long
writableStream.write({ type: "truncate", size });

在 OPFS 中同步讀寫檔案

此示例將檔案同步讀寫到 源私有檔案系統

以下非同步事件處理函式包含在 Web Worker 中。在接收到主執行緒的訊息後,它會:

  • 建立一個同步檔案訪問控制代碼。
  • 獲取檔案大小並建立一個 ArrayBuffer 來儲存它。
  • 將檔案內容讀入緩衝區。
  • 對訊息進行編碼並將其寫入檔案末尾。
  • 將更改持久化到磁碟並關閉訪問控制代碼。
js
onmessage = async (e) => {
  // retrieve message sent to work from main script
  const message = e.data;

  // Get handle to draft file in OPFS
  const root = await navigator.storage.getDirectory();
  const draftHandle = await root.getFileHandle("draft.txt", { create: true });
  // Get sync access handle
  const accessHandle = await draftHandle.createSyncAccessHandle();

  // Get size of the file.
  const fileSize = accessHandle.getSize();
  // Read file content to a buffer.
  const buffer = new DataView(new ArrayBuffer(fileSize));
  const readBuffer = accessHandle.read(buffer, { at: 0 });

  // Write the message to the end of the file.
  const encoder = new TextEncoder();
  const encodedMessage = encoder.encode(message);
  const writeBuffer = accessHandle.write(encodedMessage, { at: readBuffer });

  // Persist changes to disk.
  accessHandle.flush();

  // Always close FileSystemSyncAccessHandle if done.
  accessHandle.close();
};

注意:在 spec 的早期版本中,close()flush()getSize()truncate() 被不方便地指定為非同步方法。這已經 修正,但一些瀏覽器仍然支援非同步版本。

規範

規範
檔案系統
檔案系統訪問

瀏覽器相容性

api.FileSystemHandle

api.FileSystemFileHandle

api.FileSystemDirectoryHandle

api.FileSystemWritableFileStream

api.FileSystemSyncAccessHandle

另見