iT邦幫忙

2021 iThome 鐵人賽

DAY 14
1
Modern Web

前端三分鐘 X Progressive Web App 30 天製造解密系列 第 14

Progressive Web App 存取本機檔案: File System Access API (14)

  • 分享至 

  • xImage
  •  

什麼是 File System Access API?

透過這個 File System Access API 就能透過程式操作本機上的檔案,舉例來說像是開啟或儲存檔案等,部分瀏覽器會需要給予相關的權限才能進行操作,除了開啟檔案 API 本身也提供了開啟目錄並列舉檔案列表的功能。

對 Progressive Web App 也會在某些情境需要可以存取和操作本機端的檔案,Google 的 Lab 提供了底下這個編輯器可以簡單試玩:

https://googlechromelabs.github.io/text-editor/

browser-fs-access library:
https://github.com/GoogleChromeLabs/browser-fs-access

小編在幾年前剛學習 SPA 時也寫了個單頁筆記的應用,能夠快速的寫一些筆記,也附上原始碼和 Demo 連結。

原始碼: https://github.com/LinYenCheng/vue-note
Demo 連結: https://linyencheng.github.io/vue-note/

透過瀏覽器讀取本機檔案

前幾年小編其實沒有使用過 File System Access API,所以顯然在操作上其實有兩種方式,那第一種是透過原生的 input 然後指定 typefile 就可以達到讀取的效果,第二種是透過 File System Access API 的 showOpenFilePicker()

  1. 直接在 html 中加入 <input type="file" id="fileInput"> 並且簡單撰寫相關事件就能夠使用,程式碼如下:

var fileInput = document.getElementById('fileInput');

fileInput.addEventListener('change', function(e) {
    var file = fileInput.files[0];
    var textType = /text.*/;

    if (file.type.match(textType)) {
        var reader = new FileReader();

        reader.onload = function(e) {
            maindata.gridData = [];
            var objText = JSON.parse(reader.result.toString());
            objText.gridData.forEach(function(element, index) {
                maindata.gridData.push(element);
            });
            console.log(objText);
        };

        reader.readAsText(file);
    } else {
        fileDisplayArea.innerText = "File not supported!";
    }
});
  1. 使用 File System Access API 中的 showOpenFilePicker(),最後取得的 File object 包含會一個 blob 可以透過以下的方法去取得相關的值:
  • slice()
  • stream()
  • text()
  • arrayBuffer()
let fileHandle;
butOpenFile.addEventListener('click', async () => {
  [fileHandle] = await window.showOpenFilePicker({
    // 可以提供預設
    startIn: 'pictures'
  });
  const file = await fileHandle.getFile();
  const contents = await file.text();
  textArea.value = contents;
});

showOpenFilePicker 中的 startIn 提供的預設值是常見的幾個資料夾,能夠提供指定

  • desktop
  • documents
  • downloads
  • music
  • pictures
  • videos

透過瀏覽器寫入本機檔案

操作上一樣會有兩種方式,第一種是產生出一個下載連結,將 Blob 檔案透過下載的方式寫入,第二種是透過 File System Access API 的 showSaveFilePicker()

  1. 將需要寫入的內容先產生成 Blob 然後產生成下載連結,最後透過程式去點擊連結去觸發開啟選擇寫入資料夾的視窗。

function saveFile(text) {
    var url = null;
    var data = new Blob([text], {
        type: 'text/plain;'
    });
    // If we are replacing a previously generated file we need to
    // manually revoke the object URL to avoid memory leaks.
    if (url !== null) {
        window.URL.revokeObjectURL(url);
    }

    url = window.URL.createObjectURL(data);

    var link = document.getElementById('exportText');
    link.href = url;
    var filename = window.prompt("輸入檔名") || 'export';
    link.download = filename + '.txt';
    link.click();
}

  1. 透過 showSaveFilePicker() 開啟選擇寫入資料夾的視窗。

const fileHandle = await self.showSaveFilePicker({
  suggestedName: 'Untitled Text.txt',
  types: [{
    description: 'Text documents',
    accept: {
      'text/plain': ['.txt'],
    },
  }],
});

async function writeFile(fileHandle, contents) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Write the contents of the file to the stream.
  await writable.write(contents);
  // Close the file and write the contents to disk.
  await writable.close();
}

透過瀏覽器刪除本機檔案

這個之前小編就沒有試過其他方式,那透過 File System Access API 的 removeEntry() 是可以做到刪除檔案和刪除資料夾所有內容的效果。

// 刪除檔案
await directoryHandle.removeEntry('Abandoned Projects.txt');
// 刪除資料夾所有內容
await directoryHandle.removeEntry('Old Stuff', { recursive: true });

透過瀏覽器開啟目錄

File System Access API 的 showDirectoryPicker() 提供了我們操作目錄並列舉內容的功能。

const dirHandle = await window.showDirectoryPicker();
for await (const entry of dirHandle.values()) {
 console.log(entry.kind, entry.name);
}

File System Access API 權限

部分瀏覽器環境還是會有權限的問題,所以偵測權限相關就變成也是要寫在程式碼裡,邏輯如下:


async function verifyPermission(fileHandle, readWrite) {
  const options = {};
  if (readWrite) {
    options.mode = 'readwrite';
  }
  // 看是否已同意
  if ((await fileHandle.queryPermission(options)) === 'granted') {
    return true;
  }
  // 看這次有沒有要成功
  if ((await fileHandle.requestPermission(options)) === 'granted') {
    return true;
  }
  // 被拒絕
  return false;
}


上一篇
Progressive Web App 用戶端儲存簡介 (13)
下一篇
Progressive Web App Audits (15)
系列文
前端三分鐘 X Progressive Web App 30 天製造解密30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言