JS: Обработка ошибок
Теория: Информация о файле
Unix-философия гласит, что всё есть файл. То есть любое устройство, принтер, сканер и папка — это файлы. При этом нужно уметь различать типы этих файлов и проверять, чем они являются. Это нужно, чтобы была возможность работать с ними определенным образом.
Чтобы получить необходимую информацию о файле, Node.js в своем API дает для этого специальный объект — Stats. В этом уроке мы познакомимся с ним и узнаем, как с ним работать.
Информация о файле без Stats
Рассмотрим, как мы получаем информацию о файле сейчас. Мы извлекаем текущую ноду внутри и проверяем руками type:
Кроме type можно проверять что-нибудь другое.
Это нормальный рабочий подход, но тут всплывает сразу несколько неудобностей. Например, мы делаем проверку на основе строк, и если возникнет ошибка, мы не узнаем о ней. Допустим, кто-то ошибся в названии.
Также при более сложных проверках будет появляться дублирующая логика в разных местах. Поэтому здесь нужны функции, которые покажут, чем является файл, а также его дополнительные характеристики. Например, это функции isDirectory, isSocket, isSymbolicLink.
Информация о файле через Stats
Stats — это объект, в котором много разных параметров:
По ним можно узнать информацию о файле, например: когда и кем он был создан, сколько блоков занимает, кто его владелец.
Нам не понадобится такое количество параметров из примера выше. Достаточно знать, является ли что-то файлом или директорией. Но в дальнейшем это можно расширить до любой задачи, которая необходима при работе со статистикой.
Рассмотрим, как сделать правильный интерфейс. Его можно скопировать с Node.js API:
Файловая система может иметь проверку isDirectory, но внутри она уже будет работать по-другому. Она будет вызывать statSync и проверять строчку files.statSync('/etc').isDirectory();.
Идентичная работа у Stats-объекта будет и с файлами:
Так как это единый интерфейс, он содержит те же функции и для папок, и для файлов, и для всего остального. Но, например, если мы вызовем isDirectory(), где работаем с файлом, то получим false, и наоборот. То есть мы зависим от того, с чем работаем.
Полиморфизм
Внутри интерфейса было бы удобнее разделять типы, потому что так проще обеспечить полиморфизм.
Например, в примере ниже видно, что в touchSync() при вызове addChild() мы создаем новый объект класса File:
А в mkdirSync() мы создаем объект класса Dir:
То есть в первом случае мы могли бы сразу создать Stats-объект и по-разному его конфигурировать. Но тогда придется делать это везде и постоянно. А в данных примерах мы инкапсулируем эту логику и зашиваем параметры в типы. Так этим управлять проще и удобнее, а код становится чище.
Получается, что file и dir – это отдельные объекты, которые придерживаются общего типа и имеют внутри метод getStats(). То есть когда мы создаем файл, у него есть getStats(), который возвращает объект статистики. И мы можем вызвать у него уже знакомые нам методы, например, isFile() или isDirectory().
В этом случае наш statSync() будет выглядеть так:
Здесь мы извлекаем нашу ноду и достаем из нее мета.
Нужно понимать, что мета – это еще не статистика. Это new File() или new Dir(), а у него мы дальше берем getStats(). Здесь и срабатывает полиморфизм подтипов.
