В этой статье мы рассмотрим основной модуль файловой системы, файловые потоки и некоторые альтернативы модуля fs.
Представьте, что у вас есть задача, которую нужно выполнить с помощью Node.js ..
Проблема, с которой вы сталкиваетесь, кажется простой, но вместо того, чтобы проверять официальную документацию Node.js, вы отправляетесь в Google или npm и ищете модуль, который может сделать эту работу за вас.
Хотя это совершенно нормально; иногда основные модули могут легко помочь вам.
В этой новой серии Освоение основных модулей Node.js вы узнаете, какие скрытые / малоизвестные функции имеют основные модули и как их можно использовать. Мы также упомянем модули, которые расширяют свое поведение и являются отличным дополнением к вашему ежедневному процессу разработки.
Модуль Node.js fs
Файловый ввод-вывод обеспечивается простыми оболочками для стандартных функций POSIX. Чтобы использовать модуль fs
, вы должны потребовать его с require('fs')
. Все методы имеют асинхронную и синхронную формы.
Асинхронный API
// the async api
const fs = require('fs')
fs.unlink('/tmp/hello', (err) => { if (err) { return console.log(err) } console.log('successfully deleted /tmp/hello') })
При разработке производственного кода всегда следует использовать асинхронный API, поскольку он не блокирует цикл событий, чтобы вы могли создавать высокопроизводительные приложения.
Синхронный API
// the sync api
const fs = require('fs')
try { fs.unlinkSync('/tmp/hello') } catch (ex) { console.log(ex) }
console.log('successfully deleted /tmp/hello');
Вы должны использовать синхронный API только при создании проверочных концептуальных приложений или небольших интерфейсов командной строки.
Файловые потоки Node.js
Мы часто видим, что разработчики практически не используют файловые потоки.
Потоки в @nodejs - это мощные концепции - с их помощью вы можете добиться небольшого объема памяти, занимаемой вашими приложениями.
Что такое потоки Node.js?
Потоки - это первоклассная конструкция в Node.js для обработки данных. Необходимо понять три основных понятия:
- источник - объект, откуда берутся ваши данные,
- конвейер - где ваши данные проходят через (вы можете отфильтровать или изменить его здесь),
- раковина - там, где заканчиваются ваши данные.
Для получения дополнительной информации см. Руководство по потокам Substack .
Поскольку основной модуль fs не предоставляет возможности для копирования файлов, вы можете легко сделать это с помощью потоков:
// copy a file
const fs = require('fs') const readableStream = fs.createReadStream('original.txt') var writableStream = fs.createWriteStream('copy.txt')
readableStream.pipe(writableStream)
Вы можете спросить - зачем мне это делать, если это всего лишь cp
команда?
Самым большим преимуществом использования потоков в этом случае является возможность преобразовывать файлы - вы можете легко сделать что-то вроде этого, чтобы распаковать файл:
const fs = require('fs') const zlib = require('zlib')
fs.createReadStream('original.txt.gz') .pipe(zlib.createGunzip()) .pipe(fs.createWriteStream('original.txt'))
Когда не использовать fs.access
Цель метода fs.access
- проверить, есть ли у пользователя разрешения для данного файла или пути, примерно так:
fs.access('/etc/passwd', fs.constants.R_OK |
fs.constants.W_OK, (err) => {
if (err) {
return console.error('no access')
}
console.log('access for read/write')
})
Константы, доступные для проверки разрешений:
fs.constants.F_OK
- чтобы проверить, виден ли путь вызывающему процессу,fs.constants.R_OK
- чтобы проверить, может ли путь быть прочитан процессом,fs.constants.W_OK
- чтобы проверить, может ли процесс быть записан,fs.constants.X_OK
- чтобы проверить, может ли этот путь быть выполнен процессом.
Однако обратите внимание, что использовать fs.access
для проверки доступности файла перед вызовом fs.open
, fs.readFile
или fs.writeFile
не рекомендуется.
Причина проста - если вы это сделаете, вы создадите состояние гонки. Между вашей проверкой и фактической операцией с файлом другой процесс мог уже изменить этот файл.
Вместо этого вам следует открыть файл напрямую и обработать там ошибки.
Предостережения относительно fs.watch
С помощью метода fs.watch
вы можете отслеживать изменения файла или каталога.
Однако fs.watch
API не на 100% согласован для разных платформ, а в некоторых системах он вообще недоступен:
- в системах Linux используется inotify,
- в системах BSD используется kqueue,
- в OS X используется kqueue для файлов и FSEvents для каталогов,
- в системах SunOS (включая Solaris и SmartOS) здесь используются порты событий,
- в системах Windows эта функция зависит от ReadDirectoryChangesW.
Обратите внимание, что рекурсивный вариант поддерживается только в OS X и Windows, но не в Linux.
Кроме того, аргумент fileName
в обратном вызове watch
не всегда предоставляется (поскольку он поддерживается только в Linux и Windows), поэтому вам следует подготовиться к откату, если он равен undefined
:
fs.watch('some/path', (eventType, fileName) => {
if (!filename) {
//filename is missing, handle it gracefully
}
})
Полезные fs
модули от npm
Сообщество поддерживает несколько очень полезных модулей, расширяющих функциональность модуля fs
.
graceful-fs
graceful-fs
является заменой основного модуля fs
с некоторыми улучшениями:
- ставит в очередь вызовы
open
иreaddir
и повторяет их, когда что-то закрывается, если есть ошибка EMFILE из-за слишком большого количества файловых дескрипторов, - игнорирует ошибки
EINVAL
иEPERM
вchown
,fchown
илиlchown
, если пользователь не является пользователем root, - делает
lchmod
иlchown
нупами, если они недоступны, - пытается прочитать файл, если чтение приводит к
EAGAIN
ошибке.
Вы можете начать использовать его так же, как основной модуль fs
, или, альтернативно, исправив глобальный модуль.
// use as a standalone module
const fs = require('graceful-fs')
// patching the global one
const originalFs = require('fs') const gracefulFs = require('graceful-fs') gracefulFs.gracefulify(originalFs)
mock-fs
Модуль mock-fs
позволяет временно поддерживать встроенный в Node модуль fs с помощью фиктивной файловой системы в памяти. Это позволяет запускать тесты для набора фиктивных файлов или каталогов.
Начать пользоваться модулем очень просто:
const mock = require('mock-fs') const fs = require('fs')
mock({ 'path/to/fake/dir': { 'some-file.txt': 'file content here', 'empty-dir': {} }, 'path/to/some.png': new Buffer([8, 6, 7, 5, 3, 0, 9]) })
fs.exists('path/to/fake/dir', function (exists) { console.log(exists) // will output true })
lockfile
Блокировка файла - это способ ограничить доступ к файлу, разрешив доступ только одному процессу в любой момент времени. Это может предотвратить сценарии состояния гонки.
Добавление файлов блокировки с помощью модуля lockfile
несложно:
const lockFile = require('lockfile')
lockFile.lock('some-file.lock', function (err) { // if the err happens, then it failed to acquire a lock. // if there was not an error, then the file was created, // and won't be deleted until we unlock it.
// then, some time later, do: lockFile.unlock('some-file.lock', function (err) {
}) })
Заключение
Я надеюсь, что это было полезным объяснением файловой системы Node.js и ее возможностей.
Если у вас есть какие-либо вопросы по теме, дайте мне знать в разделе комментариев ниже.
Первоначально опубликовано на blog.risingstack.com 2 мая 2017 г.