Обработка файлов

JavaScript исторически был ориентирован на выполнение в браузере, где доступ к файловой системе ограничен. С появлением серверных сред, таких как Node.js, и современных фреймворков, например Fresh, работа с файлами стала более гибкой и мощной. Fresh как фреймворк для создания веб-приложений на Deno предоставляет удобные механизмы для взаимодействия с файловой системой и обработки данных на сервере.

Модуль Deno и работа с файлами

В Fresh для работы с файлами используется встроенный объект Deno, предоставляющий синхронные и асинхронные методы для чтения, записи и удаления файлов. Основные функции:

  • Чтение файлов
const data = await Deno.readTextFile("./example.txt");
console.log(data);

Метод readTextFile возвращает текстовое содержимое файла. Для работы с бинарными данными используется Deno.readFile, который возвращает Uint8Array.

  • Запись файлов
await Deno.writeTextFile("./output.txt", "Пример текста для записи");

writeTextFile создаёт файл, если он не существует, или перезаписывает существующий. Для бинарных данных применяется Deno.writeFile.

  • Удаление файлов
await Deno.remove("./output.txt");

Метод remove позволяет удалять как файлы, так и директории. Для удаления директории рекурсивно используется параметр { recursive: true }.

Работа с директориями

Создание и чтение содержимого каталогов в Fresh осуществляется с помощью методов Deno.mkdir и Deno.readDir.

await Deno.mkdir("./new_folder");
for await (const entry of Deno.readDir("./")) {
  console.log(entry.name, entry.isFile, entry.isDirectory);
}

Метод readDir возвращает асинхронный итератор объектов с информацией о файлах и папках.

Потоковая обработка файлов

Для работы с большими файлами эффективнее использовать потоки, что снижает потребление памяти. Пример чтения файла построчно:

const file = await Deno.open("./large.txt");
for await (const chunk of Deno.iter(file)) {
  console.log(new TextDecoder().decode(chunk));
}
file.close();

Использование TextDecoder и асинхронного итератора позволяет обрабатывать данные без загрузки всего файла в память.

Проверка существования файла

Перед чтением или записью полезно проверять наличие файла:

try {
  await Deno.stat("./example.txt");
  console.log("Файл существует");
} catch {
  console.log("Файл не найден");
}

Метод stat возвращает объект с информацией о файле: размер, время модификации, тип.

Управление правами доступа

Deno строго контролирует доступ к файловой системе. Любая операция требует явного разрешения. Например:

deno run --allow-read --allow-write app.ts

Флаги --allow-read и --allow-write предоставляют права на чтение и запись файлов. Без них попытка обращения к файловой системе вызовет ошибку.

Использование JSON и конфигурационных файлов

Частая задача — работа с JSON. Чтение и запись выполняется с помощью стандартных методов:

const raw = await Deno.readTextFile("./config.json");
const config = JSON.parse(raw);

config.newValue = 42;

await Deno.writeTextFile("./config.json", JSON.stringify(config, null, 2));

Метод JSON.stringify с параметрами null, 2 форматирует JSON с отступами для удобства чтения.

Обработка ошибок и безопасная работа с файлами

Все операции с файловой системой следует оборачивать в try-catch, чтобы корректно обрабатывать исключения:

try {
  const data = await Deno.readTextFile("./data.txt");
  console.log(data);
} catch (err) {
  if (err instanceof Deno.errors.NotFound) {
    console.log("Файл не найден");
  } else {
    throw err;
  }
}

Deno предоставляет набор специфичных ошибок (NotFound, PermissionDenied, AlreadyExists), позволяющих реализовать детализированную обработку.

Асинхронность и производительность

Все операции ввода-вывода в Fresh выполняются асинхронно. Использование await позволяет не блокировать поток выполнения, а при необходимости чтения нескольких файлов одновременно удобно применять Promise.all:

const files = ["file1.txt", "file2.txt"];
const contents = await Promise.all(files.map(f => Deno.readTextFile(f)));
console.log(contents);

Асинхронная обработка ускоряет работу сервера и предотвращает зависания при обращении к большим файлам.

Итоговые рекомендации

  • Предпочтительнее использовать асинхронные методы для всех операций с файлами.
  • Потоковое чтение необходимо для больших файлов, чтобы экономить память.
  • Всегда проверять существование файла перед операциями и обрабатывать исключения.
  • Для работы с JSON и конфигурациями использовать встроенные методы JSON.parse и JSON.stringify.
  • Управление правами доступа является обязательным шагом при запуске приложений на Deno.

Fresh и Deno создают современный стек для безопасной и эффективной работы с файлами, позволяя строить серверные приложения с высокой производительностью и надежностью.