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

Пользователи некоторых веб-приложений хотят не только видеть и обрабатывать данные, но и экспортировать их. Перед экспортом пользователи могут захотеть настроить отображаемые данные. Например, если данные отображаются в таблице, пользователи могут захотеть отфильтровать ненужные строки или столбцы, заполнить некоторые ячейки или изменить их значения.

Что делать с экспортированными данными? Менеджеры данных или ученые, например, используют R для преобразования экспортированных данных в красочные графики с планками погрешностей. Пользователи R также предпочитают видеть изменения, отраженные в их графиках, когда они фильтруют данные в веб-приложении. Может ли веб-приложение постоянно обновлять файл, который используется в качестве исходных данных другим инструментом?

Мое сообщение для пользователей R заключается в том, что нет необходимости менять имя файла в коде R каждый раз, когда данные экспортируются с веб-страницы, или удалять ранее экспортированные файлы в папке Загрузить. После того, как пользователь выберет выходной файл на веб-странице, вывод страницы может автоматически сохраняться в тот же файл либо через равные промежутки времени, либо в ответ на новый ввод. Давайте рассмотрим, как реализовать функцию автосохранения на веб-странице и, попутно, сравним несколько вариантов веб-страницы для создания файла.

Пример веб-приложения для редактирования и экспорта данных

В качестве иллюстрации я использую простую веб-страницу, отображающую таблицу с числами. Пользователи могут редактировать любую ячейку таблицы. Например, любое число можно заменить буквами.

У пользователей есть два варианта экспорта содержимого редактируемой таблицы:

  • загрузить их в файл с автоматически пронумерованным именем в папке Загрузки по умолчанию
  • сохранить их в файл с выбранным именем в любой папке.

Каковы образцы данных в таблице?

Это не имеет отношения к этому посту, но данные, показанные на иллюстрации, являются результатами сравнительного анализа методов, используемых для построения модели DOM. Я собрал эти данные, используя подход, описанный в моем предыдущем посте. Но для разнообразия я изменил порядок, в котором оцениваются методы, а также принудительно убрал мусор с gc() перед каждым измерением. Несмотря на эти изменения, новые результаты не отличаются от ранее опубликованных результатов.

Формат файлов с экспортируемыми данными

Ранее я описал простой способ экспорта данных с веб-страницы в файл Excel .xlsx. Поскольку это проще, на этот раз я экспортирую данные в файлы .csv, которые можно открыть в Excel одним щелчком мыши. Например, когда я нажимаю кнопку Загрузить, загружается файл DOM.csv:

Когда я нажимаю DOM.csv, он открывается в Excel:

Я не использую никакие библиотеки, потому что файл .csv прост. Но есть одна хитрость — хотя аббревиатура CSV означает значения, разделенные запятыми, Excel не распознает запятую как разделитель автоматически, вместо этого Excel ожидает точку с запятой, которая также приемлем Р.

Традиционный способ загрузки данных с веб-страницы

Содержимое веб-страницы можно загрузить с помощью HTML-элемента a с атрибутом download, указывающим предпочтительное имя файла. В моем примере приложения я использую следующий код:

// download.js
function downloadContents(contents, fileName) {
    const a = document.createElement('a');
    a.href = URL.createObjectURL(new Blob([contents]));
    a.download = fileName;
    a.click();
    URL.revokeObjectURL(a.href);
}

Файл всегда создается в папке Загрузки по умолчанию. Если в папке уже есть файл с нужным именем, существующий файл не перезаписывается. Вместо этого новому файлу дается уродливое имя, созданное путем добавления числа в скобках к желаемому имени. Например, если я трижды нажму кнопку Загрузить, будут созданы три файла:

Автоматически корректируемые имена файлов — не такая уж и плохая функция. Что плохо, так это то, что я ничего не могу сделать, чтобы предотвратить такое поведение. Невозможно обеспечить неизменное имя для загруженного файла. Это вопрос безопасности. Загрузка данных не является хорошим вариантом для пользователей, которые хотят получить вывод в файле со стабильным именем, чтобы этот файл мог одновременно использоваться другими инструментами.

Выбор папки и неизменяемое имя для файла

Когда я нажимаю кнопку Сохранить в первый раз, мне нужно выбрать папку и имя файла в стандартном диалоговом окне Сохранить как. Диалог начинается с папки, которая была выбрана в последний раз. Предлагаемое имя DOM2.csv можно заменить на любое.

Я принимаю предложенное имя и нажимаю кнопку Сохранить в диалоговом окне. Затем я изменяю таблицу и нажимаю кнопку Сохранить, выходной файл обновляется, но диалоговое окно Сохранить как больше не появляется:

Я вижу свежее содержимое в Excel:

Тот же целевой файл можно обновить без вызова диалогового окна, пока страница не будет перезагружена или файл не будет изменен в другом приложении.

Мне не нужно постоянно нажимать кнопку Сохранить, чтобы сохранить синхронизацию файла экспорта с таблицей на странице. Вместо этого я могу нажать удобную кнопку Продолжить сохранение. Затем я могу вводить значения в таблицу и быть уверенным, что все, что я ввожу, автоматически сохраняется каждые 3 секунды. Было бы не намного сложнее связать обновления с новым пользовательским вводом.

Чтобы реализовать функцию автосохранения в моем примере приложения, я использую современный API доступа к файловой системе. По сути, я повторно использую простые методы, описанные в посте команды Google.

Выводы

Элемент a с атрибутом download — не единственный вариант сохранения данных из браузера. И это не самый удобный вариант.

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

Полный код моей пробной страницы можно скачать с https://github.com/marianc000/saveFile.