Работа с файловой системой в TypeScript: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в работу с файловой системой в TypeScript

TypeScript — это строго типизированное расширение JavaScript, которое добавляет статическую типизацию и улучшает читаемость и поддерживаемость кода. Одной из ключевых задач при разработке серверных приложений является работа с файловой системой: чтение и запись файлов, создание и удаление директорий, управление потоками данных. В этой статье мы подробно разберём, как эффективно работать с файловой системой в TypeScript, используя встроенный модуль fs из Node.js.

Модуль fs предоставляет как синхронные, так и асинхронные методы для взаимодействия с файловой системой. В TypeScript мы можем воспользоваться преимуществами типизации, чтобы сделать код более надёжным и понятным. Мы рассмотрим основные операции, включая чтение, запись, проверку существования файлов, работу с директориями и обработку ошибок.

Основные операции с файлами

Чтение файлов

Для чтения содержимого файла в TypeScript можно использовать метод readFile (асинхронный) или readFileSync (синхронный). Асинхронный подход рекомендуется для неблокирующего выполнения программы.

import { readFile } from 'fs/promises';

async function readFileExample(filePath: string): Promise<string> {
  try {
    const data = await readFile(filePath, 'utf-8');
    return data;
  } catch (error) {
    console.error('Ошибка при чтении файла:', error);
    throw error;
  }
}

// Использование
readFileExample('example.txt').then(content => {
  console.log('Содержимое файла:', content);
});

Обратите внимание на использование fs/promises — это промис-обёртка, которая позволяет использовать синтаксис async/await. Тип возвращаемого значения Promise<string> явно указывает, что функция возвращает строку.

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

Запись данных в файл выполняется методами writeFile и writeFileSync. В TypeScript важно корректно обрабатывать возможные ошибки, особенно если файл защищён от записи или путь не существует.

import { writeFile, mkdir } from 'fs/promises';
import { existsSync } from 'fs';

async function writeFileExample(filePath: string, data: string): Promise<void> {
  try {
    // Проверяем, существует ли директория
    const dir = filePath.substring(0, filePath.lastIndexOf('/'));
    if (dir && !existsSync(dir)) {
      await mkdir(dir, { recursive: true });
    }
    await writeFile(filePath, data, 'utf-8');
    console.log('Файл успешно записан');
  } catch (error) {
    console.error('Ошибка при записи файла:', error);
  }
}

// Использование
writeFileExample('data/output.txt', 'Hello, TypeScript!');

В этом примере мы сначала проверяем существование директории и создаём её при необходимости с помощью mkdir с опцией recursive: true. Это позволяет избежать ошибки "ENOENT", если родительская папка не существует.

Добавление данных в конец файла

Если нужно дописать данные в существующий файл, используйте метод appendFile:

import { appendFile } from 'fs/promises';

async function appendToFile(filePath: string, data: string): Promise<void> {
  try {
    await appendFile(filePath, '\n' + data, 'utf-8');
    console.log('Данные добавлены');
  } catch (error) {
    console.error('Ошибка при добавлении:', error);
  }
}

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

Создание и удаление директорий

Для создания директорий используется mkdir, для удаления — rmdir или rm (для рекурсивного удаления). В TypeScript удобно использовать дженерики для типизации путей.

import { mkdir, rmdir, rm } from 'fs/promises';
import { existsSync } from 'fs';

async function createDirectory(dirPath: string): Promise<void> {
  if (!existsSync(dirPath)) {
    await mkdir(dirPath, { recursive: true });
    console.log('Директория создана');
  } else {
    console.log('Директория уже существует');
  }
}

async function removeDirectory(dirPath: string, recursive: boolean = false): Promise<void> {
  try {
    if (recursive) {
      await rm(dirPath, { recursive: true, force: true });
    } else {
      await rmdir(dirPath);
    }
    console.log('Директория удалена');
  } catch (error) {
    console.error('Ошибка при удалении:', error);
  }
}

Чтение содержимого директории

Метод readdir возвращает массив имён файлов и папок. Для фильтрации только файлов или только папок можно использовать stat.

import { readdir, stat } from 'fs/promises';

interface FileInfo {
  name: string;
  isDirectory: boolean;
  size: number;
}

async function listDirectory(dirPath: string): Promise<FileInfo[]> {
  try {
    const files = await readdir(dirPath);
    const fileInfos: FileInfo[] = [];

    for (const file of files) {
      const fullPath = `${dirPath}/${file}`;
      const stats = await stat(fullPath);
      fileInfos.push({
        name: file,
        isDirectory: stats.isDirectory(),
        size: stats.size
      });
    }

    return fileInfos;
  } catch (error) {
    console.error('Ошибка при чтении директории:', error);
    return [];
  }
}

// Использование
listDirectory('./').then(files => {
  files.forEach(f => {
    console.log(`${f.name} - ${f.isDirectory ? 'папка' : 'файл'} (${f.size} байт)`);
  });
});

Обратите внимание на интерфейс FileInfo — это пример типизации, которая делает код самодокументируемым и безопасным.

Обработка ошибок и типизация

Типы ошибок Node.js

При работе с файловой системой часто возникают ошибки: файл не найден (ENOENT), недостаточно прав (EACCES), диск переполнен (ENOSPC). В TypeScript можно создать кастомные типы для обработки ошибок.

import { readFile } from 'fs/promises';

type FileError = {
  code: string;
  message: string;
};

async function safeReadFile(filePath: string): Promise<string | FileError> {
  try {
    const data = await readFile(filePath, 'utf-8');
    return data;
  } catch (error: any) {
    return {
      code: error.code || 'UNKNOWN',
      message: error.message || 'Неизвестная ошибка'
    };
  }
}

// Использование с проверкой типа
const result = await safeRead                

Блоги

Рекомендаций по книгам