How do I save a file to a specific directory in JavaScript?

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 FileSystemHandle class helps define two child classes: FileSystemFileHandle and 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

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

async function getTheFile() {
  // open file picker
  [fileHandle] = await window.showOpenFilePicker(pickerOpts);

  // get file contents
  const fileData = await fileHandle.getFile();
}
0 and
const pickerOpts = {
  types: [
    {
      description: 'Images',
      accept: {
        'image/*': ['.png', '.gif', '.jpeg', '.jpg']
      }
    },
  ],
  excludeAcceptAllOption: true,
  multiple: false
};

async function getTheFile() {
  // open file picker
  [fileHandle] = await window.showOpenFilePicker(pickerOpts);

  // get file contents
  const fileData = await fileHandle.getFile();
}
1. 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:

  • The
    const pickerOpts = {
      types: [
        {
          description: 'Images',
          accept: {
            'image/*': ['.png', '.gif', '.jpeg', '.jpg']
          }
        },
      ],
      excludeAcceptAllOption: true,
      multiple: false
    };
    
    async function getTheFile() {
      // open file picker
      [fileHandle] = await window.showOpenFilePicker(pickerOpts);
    
      // get file contents
      const fileData = await fileHandle.getFile();
    }
    
    2 method of the HTML Drag and Drop API.
  • The File Handling API.

Each handle provides its own functionality and there are a few differences depending on which one you are using (see the 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: 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 FileSystemHandle can also be serialized into an IndexedDB database instance, or transferred via

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

async function getTheFile() {
  // open file picker
  [fileHandle] = await window.showOpenFilePicker(pickerOpts);

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

The is a storage endpoint private to the origin of the page, providing optional access to a special kind of file that is highly optimized for performance, for example, by offering in-place and exclusive write access to a file's content.

Storing data in the OPFS is similar to storing data in any other browser-provided storage mechanism that's private to the origin of the page (for example the IndexedDB API). This means that files in the OPFS differ from files selected using a picker in the following ways:

  • Permission prompts are not required to access files in the OPFS.
  • Clearing data for the site deletes the OPFS.
  • The OPFS is subject to browser quota restrictions.

Files can be manipulated inside the OPFS via a three-step process:

  1. The
    const pickerOpts = {
      types: [
        {
          description: 'Images',
          accept: {
            'image/*': ['.png', '.gif', '.jpeg', '.jpg']
          }
        },
      ],
      excludeAcceptAllOption: true,
      multiple: false
    };
    
    async function getTheFile() {
      // open file picker
      [fileHandle] = await window.showOpenFilePicker(pickerOpts);
    
      // get file contents
      const fileData = await fileHandle.getFile();
    }
    
    5 method, which is obtained using
    const pickerOpts = {
      types: [
        {
          description: 'Images',
          accept: {
            'image/*': ['.png', '.gif', '.jpeg', '.jpg']
          }
        },
      ],
      excludeAcceptAllOption: true,
      multiple: false
    };
    
    async function getTheFile() {
      // open file picker
      [fileHandle] = await window.showOpenFilePicker(pickerOpts);
    
      // get file contents
      const fileData = await fileHandle.getFile();
    }
    
    6 in a worker or the main thread, returns a reference to a FileSystemDirectoryHandle object allowing access to a directory and its contents — this represents the root of the OPFS.
  2. The
    const pickerOpts = {
      types: [
        {
          description: 'Images',
          accept: {
            'image/*': ['.png', '.gif', '.jpeg', '.jpg']
          }
        },
      ],
      excludeAcceptAllOption: true,
      multiple: false
    };
    
    async function getTheFile() {
      // open file picker
      [fileHandle] = await window.showOpenFilePicker(pickerOpts);
    
      // get file contents
      const fileData = await fileHandle.getFile();
    }
    
    8 method is invoked to return a FileSystemFileHandle object representing a handle to a specific file in the directory.
  3. The
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    0 method is invoked on that file handle, and returns a
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    1 object that can be used to read and write to the file. This is a high-performance handle for synchronous read/write operations (the other handle types are asynchronous). The synchronous nature of this class brings performance advantages intended for use in contexts where asynchronous operations come with high overhead (for example, WebAssembly). Note that it is only usable inside dedicated Web Workers.

While browsers typically implement this by persisting the contents of the OPFS to disk somewhere, it is not intended that the contents be easily user-accessible. While the browser might make it seem that there are files, they might be stored in a database or any other data structure. You cannot expect to find the created files matched one-to-one somewhere on the hard disk.

Note: Writes performed using

const dirName = 'directoryToGetName';

// assuming we have a directory handle: 'currentDirHandle'
const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
2 are in-place, meaning that changes are written to the actual underlying file at the same time as they are written to the writer. This is not the case with other writing mechanisms available in this API (e.g.
const dirName = 'directoryToGetName';

// assuming we have a directory handle: 'currentDirHandle'
const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
3), where changes are not committed to disk until the writing stream is closed.

There is also "save" functionality:

  • In the case of the asynchronous handles, use the
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    4 interface. Once the data you'd like to save is in a format of
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    5,
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    6 object, string literal or
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    7, you can open a stream and save the data to a file. This can be the existing file or a new file.
  • In the case of the synchronous
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    1, you write changes to a file using the
    const dirName = 'directoryToGetName';
    
    // assuming we have a directory handle: 'currentDirHandle'
    const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
    
    9 method. You can optionally also call
    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 directory 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);
        }
      }
    }
    
    0 if you need the changes committed to disk at a specific time (otherwise you can leave the underlying operating system to handle this when it sees fit, which should be OK in most cases).

FileSystemHandle

The FileSystemHandle interface is an object which represents an entry. Multiple handles can represent the same entry. For the most part you do not work with FileSystemHandle directly but rather its child interfaces FileSystemFileHandle and FileSystemDirectoryHandle.

FileSystemFileHandle

Provides a handle to a file system entry.

FileSystemDirectoryHandle

provides a handle to a file system directory.

const dirName = 'directoryToGetName';

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

Provides a synchronous handle to a file system entry, which operates in-place on a single file on disk. The synchronous nature of the file reads and writes allows for higher performance for critical methods in contexts where asynchronous operations come with high overhead, e.g., WebAssembly. This class is only accessible inside dedicated Web Workers for files within the .

const dirName = 'directoryToGetName';

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

is a

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();
}
0 object with additional convenience methods, which operates on a single file on disk.

The below code allows the user to choose a file from the file picker and then tests to see whether the handle returned is a file or directory

// store a reference to our file handle
let fileHandle;

async function getFile() {
  // open file picker
  [fileHandle] = await window.showOpenFilePicker();

  if (fileHandle.kind === 'file') {
    // run file code
  } else if (fileHandle.kind === 'directory') {
    // run directory code
  }

}

The following asynchronous function presents a file picker and once a file is chosen, uses the

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();
}
1 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
  [fileHandle] = await window.showOpenFilePicker(pickerOpts);

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

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

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

The following asynchronous function opens the save file picker, which returns a FileSystemFileHandle once a file is selected. A writable stream is then created using the

const dirName = 'directoryToGetName';

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

A user defined

const dirName = 'directoryToGetName';

// assuming we have a directory handle: 'currentDirHandle'
const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
5 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

const dirName = 'directoryToGetName';

// assuming we have a directory handle: 'currentDirHandle'
const subDir = currentDirHandle.getDirectoryHandle(dirName, {create: true});
9 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 });

This example synchronously reads and writes a file to the .

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

  • Creates a synchronous file access handle.
  • Gets the size of the file and creates an
    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();
    }
    
    7 to contain it.
  • Reads the file contents into the buffer.
  • Encodes the message and writes it to the end of the file.
  • Persists the changes to disk and closes the access handle.

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,

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();
}
8,
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 directory 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);
    }
  }
}
0,
// 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 });
0, and
// 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 });
1 were wrongly specified as asynchronous methods. This has now been amended, but some browsers still support the asynchronous versions.

How to save file in specific folder in JavaScript?

you can also use window. showDirectoryPicker() to ask for a specific folder and ask for write permission to that folder... then you can write data to wherever you want without prompting the user further. this new picker should have an option for hinting where it should save a file.

How do I save a file to a specific location?

Type the combination Shift+Ctrl+s, typing all three keys simultaneously. Both methods will launch the File Save dialog to allow the user to name the file, select a folder (also called a directory) for the file and choose a file format type.

How do I save a file to a specific folder in node JS?

You then use the writeFile() function of the fs module to create a file and write data to it. The first argument is the file path. As you provided just the file name, Node. js will create the file in the same directory that you're executing the code in.

How to save file with JavaScript?

Algorithm.
Step 1 − Create HTML <a> element..
Step 2 − Get content to add to the text file..
Step 3 − Create a Blob object of the content..
Step 4 − In the href attribute of the <a> tag, add the blog object URL..
Step 5 − Add the default file name as a value of the 'download' attribute of <a> tag..