Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File System Access API: is it possible to store the fileHandle of a saved or loaded file for later use?

Working on an app that uses the new(ish) File System Access API, and I wanted to save the fileHandles of recently loaded files, to display a "Recent Files..." menu option and let a user load one of these files without opening the system file selection window.

This article has a paragraph about storing fileHandles in IndexedDB and it mentions that the handles returned from the API are "serializable," but it doesn't have any example code, and JSON.stringify won't do it.

File handles are serializable, which means that you can save a file handle to IndexedDB, or call postMessage() to send them between the same top-level origin.

Is there a way to serialize the handle other than JSON? I thought maybe IndexedDB would do it automatically but that doesn't seem to work, either.

like image 893
Charles Johnson Avatar asked Jan 27 '21 22:01

Charles Johnson


People also ask

What is file system access?

Allowing an app to have file system access enables it to have access to the same files and folders to which you have access. The app must request this access, and you can choose to allow or deny the request. Allowing access to your file system might give apps access to personal content that you want to manage.

Does Firefox support file system access API?

The original File System API was created to let browsers implement support for accessing a sandboxed virtual file system on the user's storage device.

Can I use file and directory entries API?

In Chrome, you can use the File and Directory Entries API with the Quota Management API, which lets you ask for more storage and manage your storage quota.

Can mobile web application can access device file system?

Because the file system is sandboxed, a web app cannot access another app's files. You also cannot read or write files to an arbitrary folder (for example, My Pictures and My Documents) on the user's hard drive.


2 Answers

Here is a minimal example that demonstrates how to store and retrieve a file handle (a FileSystemHandle to be precise) in IndexedDB (the code uses the idb-keyval library for brevity):

import { get, set } from 'https://unpkg.com/[email protected]/dist/esm/index.js';

const pre = document.querySelector('pre');
const button = document.querySelector('button');

button.addEventListener('click', async () => {
  try {
    const fileHandleOrUndefined = await get('file');    
    if (fileHandleOrUndefined) {      
      pre.textContent =
          `Retrieved file handle "${fileHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    // This always returns an array, but we just need the first entry.
    const [fileHandle] = await window.showOpenFilePicker();
    await set('file', fileHandle);    
    pre.textContent =
        `Stored file handle for "${fileHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

I have created a demo that shows the above code in action.

like image 147
DenverCoder9 Avatar answered Oct 16 '22 22:10

DenverCoder9


When a platform interface is [Serializable], it means it has associated internal serialization and deserialization rules that will be used by APIs that perform the “structured clone” algorithm to create “copies” of JS values. Structured cloning is used by the Message API, as mentioned. It’s also used by the History API, so at least in theory you can persist FileHandle objects in association with history entries.

In Chromium at the time of writing, FileHandle objects appear to serialize and deserialize successfully when used with history.state in general, e.g. across reloads and backwards navigation. Curiously, it seems deserialization may silently fail when returning to a forward entry: popStateEvent.state and history.state always return null when traversing forwards to an entry whose associated state includes one or more FileHandles. This appears to be a bug.

History entries are part of the “session” storage “shelf”. Session here refers to (roughly) “the lifetime of the tab/window”. This can sometimes be exactly what you want for FileHandle (e.g. upon traversing backwards, reopen the file that was open in the earlier state). However it doesn’t help with “origin shelf” lifetime storage that sticks around across multiple sessions. The only API that can serialize and deserialize FileHandle for origin-level storage is, as far as I’m aware, IndexedDB.

like image 43
Semicolon Avatar answered Oct 16 '22 20:10

Semicolon