NodeJS работа с файлами

50

Доброго времени суток, друзья. Поговорим сегодня о работе с файлами в Node.js. Для работы с файлами используется модуль fs (сокращение от File System).

В этой статье мы рассмотрим следующие темы:

— Работа с файловыми дескрипторами;

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

— Создание новой папки;

— Чтение содержимого папки;

— Удаление папки;

— Получение системной информации о файле;

— Модуль path и путь к файлу;

— Получение имени, пути и расширения файла;

— Работа с путями файла;

— Переименование файла или директории;

— Чтение файла;

— Запись файла;

— Копирование файла;

— Удаление файла.

Для начала работы нам потребуется установленная Node.js. Подробную инструкцию по ее установке вы можете получить (тут). 

Прежде чем начать работу с модулем, его следует импортировать в рабочем файле. 

Пример:


const fs = require(‘fs');

Пробежимся по основным методам этого модуля и посмотрим на примерах как с ними можно работать.

Работа с файловыми дескрипторами  

Прежде чем двигаться дальше, давайте посмотрим на термины, о которых описано в статье ниже.

Файловый дескриптор — это неотрицательное целое число. Когда создается новый поток ввода-вывода, ядро возвращает процессу, создавшему поток ввода-вывода, его файловый дескриптор (Wikipedia).

Если излагать простыми словами, то при открытии файла мы получаем его дескриптор — это уникальный индикатор, благодаря которому мы можем отслеживать каждый файл отдельно и работать с ним. Для получения дескриптора файла в Node.js используются два метода: (1) асинхронный метод fs.open() и (2) синхронный fs.openSync(). К слову все методы в Node.js имеют синхронные и асинхронные реализации. Синхронные методы отмечены в название метода с окончанием Sync. В чем же разница между синхронным и асинхронным методами? Главное отличие — это порядок их выполнения. Синхронный метод будет выполнен путем блокирования основного потока, в тоже время, если для того же действия использовать ассинхронный метод, то операции могут быть выполнены в произвольном порядке по истечению их выполнения (т.к. основной поток не будет блокироваться).

Перейдем к примерам.


const fs = require('fs')

// асинхронный
fs.open('template.txt', 'r', (err, fd) => {
    if (err) throw err;
    //fd - это дескриптор файла
    console.log(fd)
})

// синхронный 
try {
  const fd = fs.openSync('template.txt', 'r')
  console.log(fd)
} catch (err) {
  console.error(err)
}

В этих примерах при выполнении кода, мы получим уникальный дескриптор файла. Пройдемся по параметрам методов. Первый — это путь к файлу, который читаем. Второй параметр предназначен для передачи флагов доступа к файлам. В данном примере мы указали параметр ‘r’, что означает этот файл открыт для чтения.

Ниже я приведу перечень флагов доступа к файлам

r — чтение;

r+ — чтение и запись;

w+ — чтение и запись, запись с начала файла. Файл создается если его нет;

a —  запись, запись с конца файла. Файл создается если его нет;

a + — чтение и запись, запись с конца файла. Файл создается если его нет;

Третий параметр отличается в зависимости от типа метода. В асинхронном варианте это колбэк функция, первый аргумент которой возвращает ошибку (в случае ее возникновения), а второй — сам дескриптор. Если метод синхронный, то вызов происходит в блоке try/catch для отслеживания ошибок и получения ответа путем присвоения вызова переменной.

Следует помнить, что дескрипторы файлов необходимо закрывать для предотвращения переполнения памяти, а также проблем с производительностью. Выполним данную задачу с помощью метода close() и его синхронного аналога closeSync().

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

Для проверки существующей директории (файла) и доступов к нему в модуле fs применяется метод access

Пример:


const fs = require('fs')
const file = 'package.json';

// проверка существования файла
fs.access(file, fs.constants.F_OK, (err) => {
  console.log(`${file} ${err ? 'не существует' : 'существует'}`);
});

// проверка на возможность прочитать файл
fs.access(file, fs.constants.R_OK, (err) => {
    console.log(`${file} ${err ? 'не прочитать' : 'прочитать'}`);
});
  
// проверка на возможность перезаписать файл
fs.access(file, fs.constants.W_OK, (err) => {
    console.log(`${file} ${err ? 'не перезаписать' : 'перезаписать'}`);
});

Вторым параметром устанавливается константа режима проверки:

F_OK — существование файла без проверки прав доступа;

R_OK — может ли файл быть прочитан текущим процессом;

W_OK — может ли файл быть записан текущим процессом;

X_OK — может ли файл быть выполнен текущим процессом (в Windows не работает).

Создание новой папки

Для создания каталогов присутствует асинхронный метод mkdir и синхронный mkdirSync.

Пример:


fs.mkdir(__dirname + dir, { recursive: true }, (err) => {
    if (err) {
        console.error(err)
        return
    }
})

if (!fs.existsSync(dir)) {
    try {
      fs.mkdirSync(__dirname + dir, { recursive: true })
    } catch (error) {
        console.error(error)
    }
} else {
    console.log('Папка существует')
}

Для создания в текущей директории нового каталога, перед путем следует указать переменную __dirname как вариант реализации абсолютного пути, либо воспользоваться метом resolve модуля path.

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

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

Пример:


const fs = require('fs')
const dir =  __dirname + '/'

fs.readdir(dir, (err, files) => {
    if (err) {
      console.error(err)
      return
    }
    console.log(files)
})

try {
    const files = fs.readdirSync(dir)
    console.log(files)
} catch (error) {
      console.error(error)
}

Удаление папки

Удаление директории производится с помощью методов rmdir и rmdirSync. Первым параметром методов является путь удаляемой директории.

Пример:


const fs = require('fs')

fs.rmdir(__dirname +'/testDel', () => { 
    console.log('Файл успешно удален')
})

try {
    fs.rmdirSync(__dirname + '/testDel')
    console.log('Файл успешно удален')
} catch (error) {
    console.error(error)
}

Получение системной информации о файле 

Каждый файл, который мы загружаем, помимо данных хранит в себе системную информацию. Для получения этой информации можно воспользоваться методом stat() или выбрать синхронный вариант statSync()

Пример:


// асинхронный
fs.stat('template.txt', (err, stats) => {
    if (err) {
        console.error(err)
        return
    }
    console.log(stats)
})

// синхронный
try {
  const stats = fs.statSync('template.txt')
  console.log(stats)
} catch (err) {
  console.error(err)
}

Вся информация хранится в получаемом объекте stats. Данный объект хранит в себе методы для получения дополнительной полезной информации.

Перечислю некоторые из этих свойств:

stats.isDirectory() метод позволяет узнать, является ли файл директорией;

stats.isFile() метод возвращает true, если это файл;

stats.isSocket() метод возвращает true, если это сокет;

stats.isSymbolicLink() метод возвращает true, если файл является символьной ссылкой;

stats.size свойство, которое возвращает размер файла;

stats.birthtime возвращает время и дату, когда данный файл был создан.

Пример: 


fs.stat('template.txt', (err, stats) => {
    if (err) {
        console.error(err)
        return
    }
    console.log(stats.isDirectory())
    console.log(stats.isFile())
    console.log(stats.isSocket())
    console.log(stats.isSymbolicLink())
    console.log(stats.size)
    console.log(stats.mode)
    console.log(stats.birthtime)
})

Модуль path и путь к файлу Node.js

Основной проблемой при работе с файлами и папками в операционных системах является разный синтаксис написания путей их расположения. Для решения этой проблемы в Node.js есть модуль path c набором полезных методов.

Для началы работы с модулем его нужно импортировать.

Пример:


const path = require(‘path');

Получение имени, пути и расширения файла

Предположим, что в папке /temp лежит файл template.txt. Воспользуемся методами модуля path для получения имени файла, пути к нему, а так же его расширения. 

Пример:


const file = ‘/temp/tempalate.txt'

path.basename(file) // tempalate.txt

Метод basename возвращает наименование файла. Первым параметром передается путь к файлу, вторым параметром (опционально) передается расширение файла, если необходимо получить наименование файла без расширения.

Пример:


path.basename(file, ‘.txt’) // tempalate

path.basename(file, ‘.txt’) // tempalate

Метод dirname возвращает весь путь директории, где лежит файл и имеет один параметр, в который передается путь к файлу.

Пример:


path.dirname(file) // /temp

Метод extname возвращает расширение переданного файла.

Пример:


path.extname(file) // .txt

Работа с путями файла

В модуле path есть ряд методов для удобного формирования путей к нужному файлу или директории. Мы не будем рассматривать все методы, а только наиболее часто используемые. Рассмотрим их ниже.

Метод join принимает список параметров, объединяет их в одну строку, используя разделитель, подходящий к конкретной операционной системе, в которой будет исполнятся код.

Пример:


const folderName = 'temp'
path.join('/', folderName, ‘template.txt') // /temp/template.txt

Метод resolve используется для нахождения абсолютных путей к файлу.

Пример:


path.resolve(‘template.txt') // Users/Desktop/dev/node-fs/template.txt
path.resolve(folderName, ‘template.txt’) // /Users/Desktop/dev/node-fs/temp/template.txt
path.resolve('/temp', ‘template.txt') // /temp/template.txt

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

Пример:


path.normalize(‘/users/../temp/template.txt')
// temp/template.txt

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

Методы rename() и renameSync() первым параметром принимают путь к файлу, который нужно переименовать. Второй параметр отвечает за новое наименование файла. 

Пример:


const fs = require('fs')

// переименовываем файла
fs.rename('oldFile.txt', 'newFile.txt', (err) => {
    if (err) throw err;
    console.log('Файл переименован');
});

// переименовываем директорию
try {
    fs.renameSync('./oldDir', './newDir')
    console.log('Папка переименован');
} catch (error) {
      console.error(error)
}

Чтение файла

Пример:


const fs = require('fs')

// асинхронное
fs.readFile(‘template.txt', ‘utf-8’, (err, data) => {
    if (err) {
      console.error(err)
      return
    }
    console.log(data)
})

// синхронное
try {
    const data = fs.readFileSync(‘template.txt', 'utf-8')
    console.log(data)
} catch (err) {
    console.error(err)
}

Если вторым параметром не указана кодировка, то возвращается Buffer. Эти методы полностью загружают файлы в память компьютера, что может сильно отразиться на производительности. Если размер файла большой, то стоит воспользоваться потоками fs.createReadStream()

Запись файла 

Чтобы перезаписать контент файлов, используются методы writeFile и writeFileSync. Важный момент! Если файла, контент которого нужно перезаписать, не существует, то он будет создан автоматически.

Пример:


const fs = require('fs')
const content = 'Новый текст'

fs.writeFile('newText.txt', content, (err) => {
  if (err) {
    console.error(err)
    return
  }
  console.log('файл успешно перезаписан')
})

try {
    fs.writeFileSync('newTextTwo.txt', content)
    console.log('файл успешно перезаписан')
} catch (err) {
    console.error(err)
}

Копирование файла 

Методы copyFile() и copyFileSync() первым параметром принимают путь файла для копирования. Второй параметр принимает название пути и нового файла. Третьим параметром является колбэк функция, которая возвращает ошибку.

Пример:


const fs = require('fs')

fs.copyFile('oldFile.txt', 'oldFileTwo.txt', (err) => {
    if (err) {
        console.error(err)
        return
    }
    console.log('Файл успешно копирован')
});

try {
    fs.copyFileSync('oldFile.txt', 'oldFileTwo.txt')
    console.log('Файл успешно копирован')
} catch (error) {
    console.error(error)
}

Удаление файла 

Последнее, что мы рассмотрим в этой статье будут методы unlink() и unlinkSync(). Первым параметром методы принимают путь к удаляемому файлу. Второй параметр в методе unlink возвращает колбэк функцию с ошибкой.

Пример:


const fs = require('fs')

fs.unlink('file.txt', (err) => {
    if (err) throw err;
    console.log('Файл успешно удален');
});

try {
    fs.unlinkSync('file.txt')
    console.log('Файл успешно удален');
} catch (error) {
    console.error(error)
}

Заключение

В данной статье мы разобрали работу Node.js с файлами, на примерах посмотрели основные полезные методы модулей fs и path. Исходный код вы сможете найти тут. Надеюсь данная статья была вам полезна. Учитесь, думайте, пишите код. Удачного кодинга, друзья!

Полезные ссылки:

https://nodejs.org/en/ — официальный сайт node.js

Подписывайтесь на наш канал в Telegram для получения самой последней и актуальной информации. 

0

Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *