Перейти к содержанию

Файлы

Для работы с файлами в Node.js используется встроенный модуль fs, который выполняет все синхронные и асинхронные операции ввода/вывода применительно к файлам. Чтение и запись файла могут осуществляться одним из двумя способов:

  • с использованием Buffer;
  • через создание соответствующего потока.

Чтение файлов и директорий

Для чтения файла в асинхронном режиме используется метод Node.js readFile(), который принимает три параметра:

  • путь к файлу;
  • кодировка;
  • callback-функция, вызываемая после получения содержимого файла.
fs.readFile('files/data.txt', 'utf8', (err, data) => {
  if (err) throw err

  console.log(data)
})

Callback-функции передается два аргумента: ошибка и полученные данные в строковом формате. Если операция прошла успешна, то в качестве ошибки передается null.

Если в readFile() не указать кодировку, то данные файла будут возвращены в формате Buffer.

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

const content = fs.readFileSync('files/data.txt', 'utf8')
console.log(content)

Node.js readFileSync() возвращает результат чтения файла и принимает два параметра:

  • путь к файлу;
  • кодировку.

Обработка и перехват ошибок при использовании readFileSync() осуществляется с помощью конструкции try{...}catch(){...}.

try {
  const content = fs.readFileSync('files/data.txt', 'utf8')
  console.log(content)
} catch (e) {
  console.log(e)
}

Чтобы инициировать ошибку, укажите неправильный путь к файлу.

Методы readFile() и readFileSync() для работы с файлами используют Buffer. Но есть и другой способ считать содержимое файла: создать поток с помощью Node.js fs.createReadStream(). Любой поток в Node.js является экземпляром класса EventEmitter, который позволяет обрабатывать возникающие в потоке события.

Параметры, принимаемые fs.createReadStream():

  • путь к файлу;
  • объект со следующими настройками:
  • encoding - кодировка (по умолчанию utf8);
  • mode - режим доступа (по умолчанию 0o666);
  • autoClose - если true, то при событиях error и finish поток закроется автоматически (по умолчанию true).
const stream = fs.createReadStream('files/data.txt', 'utf8')
stream.on('data', data => console.log(data))
stream.on('error', err => console.log(`Err: ${err}`))

Вместо объекта настроек можно передать строку, которая будет задавать кодировку.

Использование потока имеет ряд преимуществ перед Buffer:

  • Меньшее использование памяти за счет чтения содержимого по частям;
  • Для объемных файлов время между запросом и ответом существенно сокращается за счет того, что данные начинают поступать по частям, а не после полной загрузки;
  • Возможность перенаправить данные в другой поток с помощью метода pipe().

Для чтения директорий используются методы readdir() и readdirSync(), для асинхронного и синхронного режимов соответственно.

Node.js readdir() работает асинхронно и принимает три аргумента:

  • путь к директории;
  • кодировку;
  • callback-функцию, которая принимает аргументами ошибку и массив файлов директории (при успешном выполнении операции ошибка передается как null).
fs.readdir('files', 'utf8', (err, files) => {
  if (err) throw err

  console.log(files)
})

Node.js readdirSync() работает синхронно, возвращает массив найденных файлов и принимает два параметра:

  • путь к директории;
  • кодировку.
try {
  const files = fs.readdirSync('files', 'utf8')
  console.log(files)
} catch (e) {
  console.log(e)
}

Создание и запись файлов и директорий

В Node.js файлы могут быть записаны также синхронно и асинхронно. Для асинхронной записи имеется метод writeFile(), принимающий следующие аргументы:

  • путь к файлу;
  • данные для записи;
  • параметры записи:
  • кодировка (по умолчанию utf8);
  • права доступа (по умолчанию 0o666);
  • callback-функция, которая вызывается по завершению операции и единственным аргументом принимает ошибку (в случае успешной записи передается null).
fs.writeFile('files/data.txt', 'File Content', 'utf8', err => {
  if (err) throw err

  console.log('Done')
})

Если нет необходимости указывать параметры записи, то третьим параметром Node.js writeFile() можно сразу передать callback-функцию.

Для синхронной записи Node.js файла используйте writeFileSync(). Метод принимает все те же аргументы, что и writeFile() за исключением callback-функции. В качестве значения возвращает undefined.

try {
  fs.writeFileSync('files/data.txt', 'File Content', 'utf8')
  console.log('Done')
} catch (e) {
  console.log(e)
}

Как и в случае с readFileSync() обработка ошибок происходит с помощью try{...}catch(){...}.

Методы writeFile() и writeFileSync() перезаписывают уже имеющуюся в файле информацию новыми данными. Если вам нужно внести новые данные без удаления старых, используйте методы appendFIle() и appendFileAsync(), которые имеют идентичные параметры.

fs.appendFile('files/data.txt', '\nFile Content 2', 'utf8', err => {
  if (err) throw err

  console.log('Done')
})

Для записи файла через потока ввода имеется метод fs.createWriteStream(), который возвращает поток ввода и принимает два параметра:

  • путь к файлу;
  • объект со следующими настройками:
  • encoding - кодировка (по умолчанию utf8);
  • mode - режим доступа (по умолчанию 0o666);
  • autoClose - если true, то при событиях error и finish поток закроется автоматически (по умолчанию true).
const stream = fs.createWriteStream('files/data.txt', 'utf8')

stream.on('error', err => console.log(`Err: ${err}`))
stream.on('finish', () => console.log('Done'))

stream.write('First line\n')
stream.write('Second line\n')
stream.end()

Чтобы создать директорию, используйте методы mkdir() и mkdirSync().

Node.js mkdir() работает асинхронно и принимает в качестве параметров:

  • путь к директории;
  • объект со следующими настройками:
  • recursive - если true, создает директорию и все ее родительские директории согласно указанному пути, если они еще не существуют (по умолчанию false, т. е. все родительские директории уже должны быть созданы, иначе будет сгенерирована ошибка);
  • mode - режим доступа, параметр не поддерживается на ОС Windows (по умолчанию 0o777);
  • callback-функцию, которая единственным аргументом принимает ошибку, при успешном создании директории передается null.

Вторым параметром можно сразу передать callback-функцию.

fs.mkdir('files/dir/subdir', { recursive: true }, err => {
  if (err) throw err

  console.log('Created')
})

Node.js mkdirSync() создает директорию синхронно и возвращает undefined. Обработка ошибок осуществляется через try{...}catch(){...}. Метод mkdirSync() принимает те же параметры, что и mkdir(), за исключением callback-функции.

try {
  fs.mkdirSync('files/dir/subdir', { recursive: true })
  console.log('Done')
} catch (e) {
  console.log(e)
}

Удаление файлов и директорий

Чтобы удалить в Node.js файлы используйте методы unlink() и unlinkSync().

Метод unlink() асинхронный и принимает имя файла, который нужно удалить, и callback-функцию с ошибкой в качестве параметра (null, если удаление прошло успешно).

fs.unlink('files/data.txt', err => {
  if (err) throw err

  console.log('Deleted')
})

Для синхронного удаления файла используйте unlinkSync(), которому единственным аргументом передается имя файла.

try {
  fs.unlinkSync('files/data.txt')
  console.log('Deleted')
} catch (e) {
  console.log(e)
}

Для удаления директорий имеются методы rmdir() и rmdirSync() соответственно. Они полностью идентичны unlink() и unlinkSync(), только вместо имени файла принимают имя директории.

Пример rmdir().

fs.rmdir('files/dir', err => {
  if (err) throw err

  console.log('Deleted')
})

Пример rmdirSync().

try {
  fs.rmdirSync('files/dir')
  console.log('Deleted')
} catch (e) {
  console.log(e)
}

existsSync()

Проверка наличия в Node.js файла или директории происходит с помощью метода existsSync(), который принимает путь к файлу или директории и возвращает либо true, либо false. Как вы понимаете, Node.Js existsSync() работает в синхронном режиме.

try {
  const exists = fs.existsSync('files')
  console.log('Exists: ', exists)
} catch (e) {
  console.log(e)
}

Раньше был и Node.js exists(), но сейчас он уже официально устарел и не поддерживается.