Скачивание и сохранение файлов на диск

Как сделать сохранение файла из HTML-страницы в браузере на диск? Два способа вызова из браузера диалогового окна для скачивания и сохранения файла на диск пользователя с помощью Javascript.

Современный способ

Использование API доступа к файловой системе и метода showSaveFilePicker().

Чтобы сохранить файл, следует вызвать метод showSaveFilePicker(), который возвращает обещание (promise) с FileSystemFileHandle. Этому методу можно передать желаемое имя файла, например: {posedName: 'example.txt' }.

У этого API есть ограничения: работает только когда HTML-документ отдаётся по протоколу HTTPS и открыт не в iframe.

Классический способ

Использование HTML-элемента <a> с атрибутом download.

Элемент-ссылка <a download> на странице даёт возможность пользователю кликнуть по ней, скачать и сохранить файл на свой диск. Остаётся незаметно, с помощью JavaScript, добавить такой HTML-элемент на страницу и программно кликнуть по нему для вызова диалогового окна выбора места сохранения.

Прогрессивное улучшение

В приведенном ниже методе используется API доступа к файловой системе, если он поддерживается, а в остальных случаях используется классический подход с <a download>.

const saveFile = async (blob, suggestedName) => {
  // Обнаружение поддержки браузером API.
  // API должен поддерживаться
  // и приложение не запущено в iframe.
  const supportsFileSystemAccess =
    'showSaveFilePicker' in window &&
    (() => {
      try {
        return window.self === window.top;
      } catch {
        return false;
      }
    })();
  // Если File System Access API поддерживается…
  if (supportsFileSystemAccess) {
    try {
      // Показать диалог сохранения файла.
      const handle = await showSaveFilePicker({
        suggestedName,
      });
      // Записать blob в файл.
      const writable = await handle.createWritable();
      await writable.write(blob);
      await writable.close();
      return;
    } catch (err) {
      // Обработчик исключения, когда
      // пользователь отменил скачивание файла
      if (err.name !== 'AbortError') {
        console.error(err.name, err.message);
        return;
      }
    }
  }
  // Когда API доступа к файловой системе не поддерживается…
  // Сделать blob URL.
  const blobURL = URL.createObjectURL(blob);
  // Сделать невидимый HTML-элемент `<a download>`
  // и включить его в документ
  const a = document.createElement('a');
  a.href = blobURL;
  a.download = suggestedName;
  a.style.display = 'none';
  document.body.append(a);
  // Программно кликнуть по ссылке.
  a.click();
  // Уничтожить большой blob URL
  // и удалить ссылку из документа
  // после клика по ней
  setTimeout(() => {
    URL.revokeObjectURL(blobURL);
    a.remove();
  }, 1000);
};

В обоих случаях функция сохраняет файл. Если поддерживается API доступа к файловой системе, пользователь всегда получит диалоговое окно сохранения файла, в котором он может выбрать место сохранения файла.

Когда метод пойдёт по классическому сценарию, наличие диалогового окна для выбора места сохранения файла будет зависеть от настроек браузера. Если их не менять, файлы сохраняются в папку по умолчанию (“Загрузки”/”Downloads” в профиле пользователя).