瀏覽器處理檔案和目錄已久, File API 提供了在網頁應用程式中表示檔案物件的功能。 以及透過程式輔助方式選取這些項目並存取其資料 但眼前的一刻,光澤反映出來的不是金色相片。
處理檔案的傳統方法
開啟檔案
開發人員可以透過以下方法開啟及讀取檔案:
<input type="file">
敬上
元素。
開啟檔案最簡單的方式,看起來會像下方的程式碼範例。
input
物件提供 FileList
、
在以下範例中,只包含一個
File
。
File
是特定的 Blob
種類,
而且可在 Blob 可執行的任何環境中使用。
const openFile = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
開啟目錄
如果是開啟資料夾 (或目錄),您可以設定
<input webkitdirectory>
敬上
屬性。
除此之外,其他動作的運作方式都維持不變。
先前採用的供應商名稱
webkitdirectory
不僅適用於 Chromium 和 WebKit 瀏覽器,也能在舊版 EdgeHTML 架構和 Firefox 中使用。
儲存中 (而非下載) 檔案
儲存檔案時,以往僅限於下載檔案、
這個做法之所以有效
<a download>
敬上
屬性。
有了 Blob,您可以將錨定的 href
屬性設為 blob:
網址,可從
URL.createObjectURL()
敬上
方法。
const saveFile = async (blob) => {
const a = document.createElement('a');
a.download = 'my-file.txt';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', (e) => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
問題
下載方法有很大的缺點,就是無法重複使用 開啟→編輯→儲存流程會發生,也就是說,您無法覆寫原始檔案。 而是改為建立原始檔案的新副本 每次您「儲存」時,都會先出現在作業系統的預設「下載」資料夾中。
File System Access API
File System Access API 使得開啟與儲存這兩種作業更加簡單。 這麼做也會啟用真實儲存功能,也就是說,您不僅可以選擇檔案儲存位置 也能覆寫現有檔案
開啟檔案
有了 File System Access API
開啟檔案是指對 window.showOpenFilePicker()
方法發出的一次呼叫。
這個呼叫會傳回檔案控制代碼,您可以透過 getFile()
方法取得實際的 File
。
const openFile = async () => {
try {
// Always returns an array.
const [handle] = await window.showOpenFilePicker();
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
開啟目錄
呼叫 以開啟目錄
window.showDirectoryPicker()
,可讓系統在檔案對話方塊中選取目錄。
儲存檔案
儲存檔案的方法也很簡單。
透過檔案控制代碼,您可以透過 createWritable()
建立可寫入的串流。
然後,您必須呼叫串流的 write()
方法,以便寫入 Blob 資料。
最後,呼叫其 close()
方法即可關閉串流。
const saveFile = async (blob) => {
try {
const handle = await window.showSaveFilePicker({
types: [{
accept: {
// Omitted
},
}],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
return handle;
} catch (err) {
console.error(err.name, err.message);
}
};
隆重推出 Browser-fs-access
如同 File System Access API 這項服務尚未全面開放使用。
這就是為什麼 File System Access API 是漸進式強化功能。 因此,我想要在瀏覽器支援的情況下使用 如果不是,請採用傳統做法 使用不支援的 JavaScript 程式碼下載,絕不會拖累使用者。 browser-fs-access 程式庫是我回答這項挑戰的問題
設計理念
由於 File System Access API 未來可能還會變更
而不是針對 Browser-fs-access API 進行建模。
也就是說,這個程式庫並不是 polyfill。
而是「ponyfill」
您可以 (靜態或動態) 單獨匯入任何所需功能,讓應用程式盡可能縮小。
可用方法經過適當命名
fileOpen()
、
directoryOpen()
和
fileSave()
。
在內部,程式庫功能可偵測是否支援 File System Access API。
然後匯入對應的程式碼路徑
使用 Browser-fs-access 程式庫
這三種方法十分直觀。
您可以指定應用程式可接受的 mimeTypes
或 extensions
檔案,並設定 multiple
標記
允許或禁止使用者選取多個檔案或目錄。
如需完整詳細資料,請參閱
browser-fs-access API 說明文件。
以下程式碼範例顯示如何開啟及儲存圖片檔。
// The imported methods will use the File
// System Access API or a fallback implementation.
import {
fileOpen,
directoryOpen,
fileSave,
} from 'https://unpkg.com/browser-fs-access';
(async () => {
// Open an image file.
const blob = await fileOpen({
mimeTypes: ['image/*'],
});
// Open multiple image files.
const blobs = await fileOpen({
mimeTypes: ['image/*'],
multiple: true,
});
// Open all files in a directory,
// recursively including subdirectories.
const blobsInDirectory = await directoryOpen({
recursive: true
});
// Save a file.
await fileSave(blob, {
fileName: 'Untitled.png',
});
})();
示範
您可以在 Glitch 的示範中,查看上述程式碼的實際運作情形。 其原始碼同樣可用。 基於安全考量,跨來源子頁框不允許顯示檔案選擇器, 文章中無法嵌入示範影片。
公開的 Browser-fs-access 程式庫
我的閒暇時間 可安裝的 PWA 名為 Excalidraw 一款白板工具,可讓使用者透過手繪風格輕鬆繪製圖表。 不僅回應速度飛快,而且在各種裝置 (小手機和大螢幕電腦) 上都適用。 這代表必須處理所有平台上的檔案 是否支援 File System Access API。 因此很適合使用 Browser-fs-access 程式庫。
例如,我可以在 iPhone 上開始繪圖 儲存 (技術上:由於 Safari 不支援 File System Access API,因此請下載這個檔案) 移至 iPhone 的「下載」資料夾,在我的電腦上開啟檔案 (從我的手機傳輸後), 修改檔案、以我的變更內容覆寫,或另存為新檔案。
,瞭解如何調查及移除這項存取權。 ,瞭解如何調查及移除這項存取權。 ,瞭解如何調查及移除這項存取權。實際程式碼範例
下方是 Browser-fs-access 實際使用範例。
這份節錄的資料來源
/src/data/json.ts
。
其中特別值得注意的是 saveAsJSON()
方法如何將檔案控制代碼或 null
傳遞至 Browser-fs-access
fileSave()
方法,可在指定控制代碼時覆寫該方法。
或是另存為新檔案
export const saveAsJSON = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
fileHandle: any,
) => {
const serialized = serializeAsJSON(elements, appState);
const blob = new Blob([serialized], {
type: "application/json",
});
const name = `${appState.name}.excalidraw`;
(window as any).handle = await fileSave(
blob,
{
fileName: name,
description: "Excalidraw file",
extensions: ["excalidraw"],
},
fileHandle || null,
);
};
export const loadFromJSON = async () => {
const blob = await fileOpen({
description: "Excalidraw files",
extensions: ["json", "excalidraw"],
mimeTypes: ["application/json"],
});
return loadFromBlob(blob);
};
使用者介面注意事項
無論是在 Excalidraw 還是您的應用程式中
使用者介面應會根據瀏覽器支援的情況進行調整。
如果支援 File System Access API (if ('showOpenFilePicker' in window) {}
)
除了「Save」(儲存) 按鈕外,您還可以顯示「Save As」按鈕。
下方的螢幕截圖顯示 Excalidraw 支援在 iPhone 和 Chrome 電腦版上的回應式主應用程式工具列的差異。
注意:iPhone 上缺少「另存新檔」按鈕。
結論
技術上來說,使用系統檔案完全支援所有新型瀏覽器。 在支援 File System Access API 的瀏覽器上,只要允許 適用於實際儲存及覆寫檔案 (不只是下載) 讓使用者在任何位置建立新檔案 仍可在不支援 File System Access API 的瀏覽器中正常運作。 browser-fs-access 可讓您的生活更輕鬆 處理漸進增強的細微差異,並盡可能簡化程式碼。
特別銘謝
本文經過 Joe Medley 和 Kayce Basques。 感謝 Excalidraw 貢獻者 處理專案工作 並檢閱我的提取要求 主頁橫幅製作者: Ilya Pavlov 的 Unsplash。