Как сохранить файл в javascript

JavaScript: чтение и запись файлов с помощью File System Access API

В этой небольшой статье я хочу рассказать вам о File System Access API (далее — FSA ), позволяющем читать и записывать файлы в локальную систему пользователя с помощью браузера.

Если вам это интересно, прошу под кат.

Поддержка

К сожалению, на сегодняшний день FSA поддерживается только 34.68% браузеров: сюда входят все десктопные браузеры, за исключением Firefox .

Возможности

FSA расширяет объект window следующими методами:

  • showOpenFilePicker — для чтения файлов;
  • showSaveFilePicker — для записи файлов;
  • showDirectoryPicker — для чтения директории.

Данные методы называются фабриками дескрипторов локальной файловой системы (local file system handle factories) и возвращают FileSystemHandle — сущность (entity) для работы с файлами ( FileSystemFileHandle ) или директориями ( FileSystemDirectoryHandle ), соответственно.

FileSystemHandle содержит поле kind (вид, тип), значением которого может быть либо file , либо directory , и поле name (название файла или директории).

Чтение файла

Для получения сущности для чтения файла ( FileSystemFileHandle ) используется метод showOpenFilePicker :

Общими для showOpenFilePicker и showSaveFilePicker являются настройки:

  • types?: object — разрешенные типы файлов;
  • excludeAcceptAllOption?: boolean — если имеет значение true , picker будет принимать/сохранять только файлы с типами, определенными в types .

Значением поля types является объект со следующими свойствами:

  • description?: string — описание типа файлов;
  • accept?: object — объект вида < MIME-тип: расширение >.

Специфичной для showOpenFilePicker настройкой является multiple?: boolean — если имеет значение true , picker будет принимать несколько файлов и возвращать массив FileSystemFileHandle .

Для чтения содержимого файла с помощью FileSystemFileHandle используется метод getFile :

getFile возвращает интерфейс File . Для преобразования blob в текст можно использовать метод text (данный метод наследуется File от интерфейса Blob ):

Предположим, что у нас имеется директория fsa-test , в которой лежит файл test.txt с текстом Hi World . Прочитаем этот файл.

Пользователь должен явно выразить намерение прочитать файл или директорию, например, нажать кнопку.

Нажимаем на кнопку. Выбираем файл test.txt . Получаем Hi World в консоли.

Создадим еще парочку файлов, например, test2.txt с текстом Bye World и test3.txt с текстом Hi World Once Again .

Прочитаем все 3 файла, запретив пользователю выбирать другие файлы.

Нажимаем на кнопку. Выбираем файлы test.txt , test2.txt и test3.txt . Получаем в консоли:

Запись файлов

Для получения сущности для записи файла ( FileSystemFileHandle ) используется метод showSaveFilePicker :

Специфичной для showSaveFilePicker является настройка suggestedName?: string — рекомендуемое название создаваемого файла.

Для записи файла с помощью FileSystemFileHandle используется метод createWritable :

Единственной доступной на сегодняшний день настройкой createWritable является keepExistingData?: boolean — если имеет значение true , picker сохраняет данные, имеющиеся в файле на момент записи, в противном случае, содержимое файла перезаписывается.

createWritable возвращает FileSystemWritableFileStream , предоставляющий метод write для записи файла:

fileData — это данные для записи.

Запишем файл test4.txt с текстом Bye World Once Again .

Нажимаем на кнопку File saver . Сохраняем файл. Видим, что в директории появился файл test4.txt с текстом Bye World Once Again .

Перезапишем содержимое файла test.txt .

Нажимаем на кнопку File picker . Выбираем файл test.txt . Нажимаем на кнопку File saver . Получаем уведомление о том, что браузер сможет манипулировать файлом test.txt до закрытия всех вкладок. Нажимаем Сохранить . Открываем test.txt . Видим, что текст Hi World изменился на Bye World (текст Hi World должен был сохраниться, поскольку мы указали настройку keepExistingData: true ).

Чтение директории

Для получения сущности для чтения директории ( FileSystemDirectoryHandle ) используется метод showDirectoryPicker :

Для перебора содержимого выбранной директории можно использовать следующие методы:

  • entries — возвращает массив массивов вида [name, handle] , где name — название сущности, а handle — FileSystemHandle ;
  • values — возвращает массив handle ;
  • keys — возвращает массив name .

Переместим файлы test2.txt , test3.txt и test4.txt в директорию text и прочитаем содержимое директории fsa-test .

Структура директории fsa-test :

Нажимаем на кнопку Directory picker . Выбираем директорию fsa-test . Получаем уведомление о том, что наш сайт сможет просматривать файлы в выбранной директории. Нажимаем Просмотреть файлы . Получаем в консоли:

Для получения FileSystemFileHandle и FileSystemDirectoryHandle , находящихся внутри выбранной директории предназначены методы getFileHandle и getDirectoryHandle , соответственно. Обязательным параметром, принимаемым этими методами, является name — название файла/директории.

Прочитаем содержимое файла test.txt и директории text .

Нажимаем на кнопку Directory picker . Выбираем директорию fsa-test . Нажимаем Просмотреть файлы . Получаем в консоли:

getFileHandle и getDirectoryHandle также принимают настройку create?: boolean — если имеет значение true , запрашиваемый файл/директория создается при отсутствии:

Удаление файла/директории

Для удаления файла или директории предназначен метод FileSystemDirectoryHandle.removeEntry . Он принимает 2 параметра:

  • name: string — название удаляемого файла/директории;
  • options? — объект с настройками:
    • recursive: boolean — если имеет значение true , удаляется сама директория и все ее содержимое (данная настройка позволяет удалять непустые директории).

    Удалим файл test.txt и директорию text :

    Нажимаем на кнопку Directory picker . Выбираем директорию fsa-test . Получаем сразу 2 уведомления от браузера. Предоставляем ему необходимые разрешения. Видим, что файл test.txt и директория text благополучно удаляются.

    Как видите, FSA предоставляет в наше распоряжение довольно интересные возможности по работе с файлами и директориями, находящимися в локальной системе пользователя. Фактически он представляет собой урезанную версию модуля fs для браузера.

    Полагаю, с ростом поддержки FSA найдет широкое применение в веб-разработке и станет прекрасным дополнением набора инструментов, включающих File API , input type=»file» и Drag and drop API .

    Пожалуй, это все, чем я хотел поделиться с вами в этой статье.

    Обратите внимание: мы рассмотрели далеко не все возможности, предоставляемые FSA , поэтому рекомендую полистать спецификацию.

    How to Save Files in JavaScript

    Learn how to create a saveAs function to download one or multiple files in JavaScript

    In the web world, saving a file or “Save As” means downloading a file to the client’s machine. There isn’t a built-in method in JavaScript that allows us to do so. What we typically do (if we have a static file link) is add an anchor element in HTML and use the download attribute to make it downloadable. Something like this:

    The problem is that we don’t always want the user to download when clicking on a link because we could have a bunch of logic before downloading or some dynamic data created without a static link. Let’s go through a few simple steps to create a saveAs function for downloading one or multiple files in JavaScript!

    Table of Contents

    Generate a file:

    Unless we have static files available publicly on the server, we need to create content using a Blob , a file-like object in JavaScript.

    Let’s create a function that will take some data as a parameter and return a new Blob text:

    Of course, a Blob object has a lot more than just a plain text type. You can learn more in the official documentation.

    Create a saveAs function:

    Let’s look at two approaches for saving/downloading a file in JavaScript:

    1. Use an Anchor element <a> :

    We can dynamically create an anchor element in JavaScript using createElement and then programmatically invoke the click event. Here is a basic example:

    But to download a file, we need to pass it download and href attributes. The download will hold the file name and extension and the href will require a URL. Let’s create a function and put all the implementation together:

    If we are using a static file with a relative path, all we need to do is this:

    Note: Download only works for same-origin URLs. Meaning, href can’t be a path different than your websites’ otherwise the behavior will change and it will redirect instead of downloading.

    If the content is generated dynamically, we’ll need to create a blob and convert it to an object URL to make it downloadable. Also, we need to release the object at the very end when no longer needed:

    Let’s improve the function to make it re-usable and have it support both options:

    2. Use file-saver library

    FileSaver.js is a great solution to saving files on the client-side without having to write our own custom code.

    First, we need to install the library:

    Then, use it as follows:

    Zip and download multiple files:

    In certain cases, we need to download multiple files in one hit. Although this can be achieved by looping through the files and triggering the saveAs function, the user experience isn’t great and we’ll end up with so many files added to the download folder.

    An alternative solution is to use JSZip, a library for creating, reading, and editing .zip files.

    First, we need to install the library:

    Then, we’ll create an async function that does the following logic:

    1. Generates multiple files using createBlog function we did earlier:

    2. Instantiate the JSZip and add the files:

    3. Generate the zip folder and as soon as it’s ready, we can call the saveAs function we did earlier:

    Here is the full function:

    See the Pen saveAs by Muhi Masri (@muhimasri) on CodePen.

    I hope you enjoyed learning from this article and if you have any questions, please leave a comment below.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *