docs.rodeo

MDN Web Docs mirror

File System API

{{securecontext_header}} {{DefaultAPISidebar("File System API")}} {{AvailableInWorkers}} 

The File System API — with extensions provided via the File System Access API to access files on the device file system — allows read, write and file management capabilities.

See Relationship to other file-related APIs for a comparison between this API, the File and Directory Entries API, and the File API.

Concepts and Usage

This API allows interaction with files on a user’s local device, or on a user-accessible network file system. Core functionality of this API includes reading files, writing or saving files, and access to directory structure.

Most of the interaction with files and directories is accomplished through handles. A parent {{domxref('FileSystemHandle')}}  class helps define two child classes: {{domxref('FileSystemFileHandle')}}  and {{domxref('FileSystemDirectoryHandle')}} , for files and directories respectively.

The handles represent a file or directory on the user’s system. You can first gain access to them by showing the user a file or directory picker using methods such as {{domxref('window.showOpenFilePicker()')}}  and {{domxref('window.showDirectoryPicker()')}} . Once these are called, the file picker presents itself and the user selects either a file or directory. Once this happens successfully, a handle is returned.

You can also gain access to file handles via:

Each handle provides its own functionality and there are a few differences depending on which one you are using (see the interfaces section for specific details). You then can access file data, or information (including children) of the directory selected. This API opens up potential functionality the web has been lacking. Still, security has been of utmost concern when designing the API, and access to file/directory data is disallowed unless the user specifically permits it (note that this is not the case with the Origin private file system, because it is not visible to the user).

[!NOTE] The different exceptions that can be thrown when using the features of this API are listed on relevant pages as defined in the spec. However, the situation is made more complex by the interaction of the API and the underlying operating system. A proposal has been made to list the error mappings in the spec, which includes useful related information.

[!NOTE] Objects based on {{domxref("FileSystemHandle")}}  can also be serialized into an {{domxref("IndexedDB API", "IndexedDB", "", "nocode")}}  database instance, or transferred via {{domxref("window.postMessage", "postMessage()")}} .

Origin private file system

The origin private file system (OPFS) is a storage endpoint provided as part of the File System API, which is private to the origin of the page and not visible to the user like the regular file system. It provides access to a special kind of file that is highly optimized for performance and offers in-place write access to its content.

The following are some possible use cases:

Read our Origin private file system for instructions on how to use it.

Saving files

Interfaces

Extensions to other interfaces

Examples

Accessing files

The below code allows the user to choose a file from the file picker.

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

The following asynchronous function presents a file picker and once a file is chosen, uses the getFile() method to retrieve the contents.

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

Accessing directories

The following example returns a directory handle with the specified name. If the directory does not exist, it is created.

const dirName = "directoryToGetName";

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

The following asynchronous function uses resolve() to find the path to a chosen file, relative to a specified directory handle.

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

Writing to files

The following asynchronous function opens the save file picker, which returns a {{domxref('FileSystemFileHandle')}}  once a file is selected. A writable stream is then created using the {{domxref('FileSystemFileHandle.createWritable()')}}  method.

A user defined {{domxref('Blob')}}  is then written to the stream which is subsequently closed.

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

The following show different examples of options that can be passed into the write() method.

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

Synchronously reading and writing files in OPFS

This example synchronously reads and writes a file to the origin private file system.

The following asynchronous event handler function is contained inside a Web Worker. On receiving a message from the main thread it:

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

[!NOTE] In earlier versions of the spec, {{domxref("FileSystemSyncAccessHandle.close()", "close()")}} , {{domxref("FileSystemSyncAccessHandle.flush()", "flush()")}} , {{domxref("FileSystemSyncAccessHandle.getSize()", "getSize()")}} , and {{domxref("FileSystemSyncAccessHandle.truncate()", "truncate()")}}  were unergonomically specified as asynchronous methods. This has now been amended, but some browsers still support the asynchronous versions.

Specifications

{{Specifications}} 

Browser compatibility

{{Compat}} 

See also

In this article

View on MDN