Запись и чтение файлов. NodeJS
Сегодня, в девятой части перевода руководства по Node.js, мы поговорим о работе с файлами. В частности, речь пойдёт о модулях fs и path - о файловых дескрипторах, о путях к файлам, о получении информации о файлах, об их чтении и записи, о работе с директориями.
Работа с файловыми дескрипторами в Node.js
Прежде чем вы сможете взаимодействовать с файлами, находящимися в файловой системе вашего сервера, вам необходимо получить дескриптор файла.
Дескриптор можно получить, воспользовавшись для открытия файла асинхронным методом open() из модуля fs:
Const fs = require("fs")
fs.open("/Users/flavio/test.txt", "r", (err, fd) => {
//fd - это дескриптор файла
})
Обратите внимание на второй параметр, r , использованный при вызове метода fs.open() . Это - флаг, который сообщает системе о том, что файл открывают для чтения. Вот ещё некоторые флаги, которые часто используются при работе с этим и некоторыми другими методами:
r+ - открыть файл для чтения и для записи.
w+ - открыть файл для чтения и для записи, установив указатель потока в начало файла. Если файл не существует - он создаётся.
a - открыть файл для записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
a+ - открыть файл для чтения и записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
Файлы можно открывать и пользуясь синхронным методом fs.openSync() , который, вместо того, чтобы предоставить дескриптор файла в коллбэке, возвращает его:
Const fs = require("fs")
try {
const fd = fs.openSync("/Users/flavio/test.txt", "r")
} catch (err) {
console.error(err)
}
После получения дескриптора любым из вышеописанных способов вы можете производить с ним необходимые операции.
Данные о файлах
С каждым файлом связан набор данных о нём, исследовать эти данные можно средствами Node.js. В частности, сделать это можно, используя метод stat() из модуля fs .
Вызывают этот метод, передавая ему путь к файлу, и, после того, как Node.js получит необходимые сведения о файле, он вызовет коллбэк, переданный методу stat() . Вот как это выглядит:
Const fs = require("fs")
fs.stat("/Users/flavio/test.txt", (err, stats) => {
if (err) {
console.error(err)
return
}
//сведения о файле содержатся в аргументе `stats`
})
В Node.js имеется возможность синхронного получения сведений о файлах. При таком подходе главный поток блокируется до получения свойств файла:
Const fs = require("fs")
try {
const stats = fs.statSync ("/Users/flavio/test.txt")
} catch (err) {
console.error(err)
}
Информация о файле попадёт в константу stats . Что это за информация? На самом деле, соответствующий объект предоставляет нам большое количество полезных свойств и методов:
Методы.isFile() и.isDirectory() позволяют, соответственно, узнать, является ли исследуемый файл обычным файлом или директорией.
Метод.isSymbolicLink() позволяет узнать, является ли файл символической ссылкой.
Размер файла можно узнать, воспользовавшись свойством.size .
Тут имеются и другие методы, но эти - самые употребимые. Вот как ими пользоваться:
Const fs = require("fs")
fs.stat("/Users/flavio/test.txt", (err, stats) => {
if (err) {
console.error(err)
return
}
stats.isFile() //true
stats.isDirectory() //false
stats.isSymbolicLink() //false
stats.size //1024000 //= 1MB
})
Пути к файлам в Node.js и модуль path
Путь к файлу - это адрес того места в файловой системе, где он расположен.
В Linux и macOS путь может выглядеть так:
/users/flavio/file.txt
В Windows пути выглядят немного иначе:
C:usersflaviofile.txt
На различия в форматах записи путей при использовании разных операционных систем следует обращать внимание, учитывая операционную систему, используемую для развёртывания Node.js-сервера.
В Node.js есть стандартный модуль path , предназначенный для работы с путями к файлам. Перед использованием этого модуля в программе его надо подключить:
▍Получение информации о пути к файлу
Если у вас есть путь к файлу, то, используя возможности модуля path , вы можете, в удобном для восприятия и дальнейшей обработки виде, узнать подробности об этом пути. Выглядит это так:
Const notes = "/users/flavio/notes.txt"
path.dirname(notes) // /users/flavio
path.basename(notes) // notes.txt
path.extname(notes) // .txt
Здесь, в строке notes , хранится путь к файлу. Для разбора пути использованы следующие методы модуля path:
dirname() - возвращает родительскую директорию файла.
basename() - возвращает имя файла.
extname() - возвращает расширение файла.
Узнать имя файла без расширения можно, вызвав метод.basename() и передав ему второй аргумент, представляющий расширение:
Path.basename(notes, path.extname(notes)) //notes
▍Работа с путями к файлам
Несколько частей пути можно объединить, используя метод path.join() :
Const name = "flavio"
path.join("/", "users", name, "notes.txt") //"/users/flavio/notes.txt"
Найти абсолютный путь к файлу на основе относительного пути к нему можно с использованием метода path.resolve() :
Path.resolve("flavio.txt")
//"/Users/flavio/flavio.txt" при запуске из моей домашней папки
В данном случае Node.js просто добавляет /flavio.txt к пути, ведущем к текущей рабочей директории. Если при вызове этого метода передать ещё один параметр, представляющий путь к папке, метод использует его в качестве базы для определения абсолютного пути:
Path.resolve("tmp", "flavio.txt")
// "/Users/flavio/tmp/flavio.txt" при запуске из моей домашней папки
Если путь, переданный в качестве первого параметра, начинается с косой черты - это означает, что он представляет собой абсолютный путь.
Path.resolve("/etc", "flavio.txt")
// "/etc/flavio.txt"
Вот ещё один полезный метод - path.normalize() . Он позволяет найти реальный путь к файлу, используя путь, в котором содержатся спецификаторы относительного пути вроде точки (.), двух точек (..), или двух косых черт:
Path.normalize("/users/flavio/..//test.txt")
// /users/test.txt
Методы resolve() и normalize() не проверяют существование директории. Они просто находят путь, основываясь на переданным им данным.
Чтение файлов в Node.js
Самый простой способ чтения файлов в Node.js заключается в использовании метода fs.readFile() с передачей ему пути к файлу и коллбэка, который будет вызван с передачей ему данных файла (или объекта ошибки):
Fs.readFile("/Users/flavio/test.txt", (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
Если надо, можно воспользоваться синхронной версией этого метода - fs.readFileSync() :
Const fs = require("fs")
try {
const data = fs.readFileSync("/Users/flavio/test.txt")
console.log(data)
} catch (err) {
console.error(err)
}
По умолчанию при чтении файлов используется кодировка utf8 , но кодировку можно задать и самостоятельно, передав методу соответствующий параметр.
Методы fs.readFile() и fs.readFileSync() считывают в память всё содержимое файла. Это означает, что работа с большими файлами с применением этих методов серьёзно отразится на потреблении памяти вашим приложением и окажет влияние на его производительность. Если с такими файлами нужно работать, лучше всего воспользоваться потоками.
Запись файлов в Node.js
В Node.js легче всего записывать файлы с использованием метода fs.writeFile() :
Const fs = require("fs")
const content = "Some content!"
fs.writeFile("/Users/flavio/test.txt", content, (err) => {
if (err) {
console.error(err)
return
}
//файл записан успешно
})
Есть и синхронная версия того же метода - fs.writeFileSync() :
Const fs = require("fs")
const content = "Some content!"
try {
const data = fs.writeFileSync("/Users/flavio/test.txt", content)
//файл записан успешно
} catch (err) {
console.error(err)
}
Эти методы, по умолчанию, заменяют содержимое существующих файлов. Изменить их стандартное поведение можно, воспользовавшись соответствующим флагом:
Fs.writeFile("/Users/flavio/test.txt", content, { flag: "a+" }, (err) => {})
Тут могут использоваться флаги, которые мы уже перечисляли в разделе, посвящённом дескрипторам. Подробности о флагах можно узнать .
Присоединение данных к файлу
Метод fs.appendFile() (и его синхронную версию - fs.appendFileSync()) удобно использовать для присоединения данных к концу файла:
Const content = "Some content!"
fs.appendFile("file.log", content, (err) => {
if (err) {
console.error(err)
return
}
//готово!
})
Об использовании потоков
Выше мы описывали методы, которые, выполняя запись в файл, пишут в него весь объём переданных им данных, после чего, если используются их синхронные версии, возвращают управление программе, а если применяются асинхронные версии - вызывают коллбэки. Если вас такое состояние дел не устраивает - лучше будет воспользоваться потоками.
Работа с директориями в Node.js
Модуль fs предоставляет в распоряжение разработчика много удобных методов, которые можно использовать для работы с директориями.
▍Проверка существования папки
Для того чтобы проверить, существует ли директория и может ли Node.js получить к ней доступ, учитывая разрешения, можно использовать метод fs.access() .
▍Создание новой папки
Для того чтобы создавать новые папки, можно воспользоваться методами fs.mkdir() и fs.mkdirSync() :
Const fs = require("fs")
const folderName = "/Users/flavio/test"
try {
if (!fs.existsSync(dir)){
fs.mkdirSync(dir)
}
} catch (err) {
console.error(err)
}
▍Чтение содержимого папки
Для того чтобы прочесть содержимое папки, можно воспользоваться методами fs.readdir() и fs.readdirSync() . В этом примере осуществляется чтение содержимого папки - то есть - сведений о том, какие файлы и поддиректории в ней имеются, и возврат их относительных путей:
Const fs = require("fs")
const path = require("path")
const folderPath = "/Users/flavio"
fs.readdirSync(folderPath)
Вот так можно получить полный путь к файлу:
Fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)
}
Результаты можно отфильтровать для того, чтобы получить только файлы и исключить из вывода директории:
Const isFile = fileName => {
return fs.lstatSync(fileName).isFile()
}
fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)).filter(isFile)
}
▍Переименование папки
Для переименования папки можно воспользоваться методами fs.rename() и fs.renameSync() . Первый параметр - это текущий путь к папке, второй - новый:
Const fs = require("fs")
fs.rename("/Users/flavio", "/Users/roger", (err) => {
if (err) {
console.error(err)
return
}
//готово
})
Переименовать папку можно и с помощью синхронного метода fs.renameSync() :
Const fs = require("fs")
try {
fs.renameSync("/Users/flavio", "/Users/roger")
} catch (err) {
console.error(err)
}
▍Удаление папки
Для того чтобы удалить папку, можно воспользоваться методами fs.rmdir() или fs.rmdirSync() . Надо отметить, что удаление папки, в которой что-то есть, задача несколько более сложная, чем удаление пустой папки. Если вам нужно удалять такие папки, воспользуйтесь пакетом fs-extra , который весьма популярен и хорошо поддерживается. Он представляет собой замену модуля fs , расширяющую его возможности.
Метод remove() из пакета fs-extra умеет удалять папки, в которых уже что-то есть.
Установить этот модуль можно так:
Npm install fs-extra
Вот пример его использования:
Const fs = require("fs-extra")
const folder = "/Users/flavio"
fs.remove(folder, err => {
console.error(err)
})
Его методами можно пользоваться в виде промисов:
Fs.remove(folder).then(() => {
//готово
}).catch(err => {
console.error(err)
})
Допустимо и применение конструкции async/await:
Async function removeFolder(folder) {
try {
await fs.remove(folder)
//готово
} catch (err) {
console.error(err)
}
}
const folder = "/Users/flavio"
removeFolder(folder)
Модуль fs
Выше мы уже сталкивались с некоторыми методами модуля fs , применяемыми при работе с файловой системой. На самом деле, он содержит ещё много полезного. Напомним, что он не нуждается в установке, для того, чтобы воспользоваться им в программе, его достаточно подключить:
Const fs = require("fs")
После этого у вас будет доступ к его методам, среди которых отметим следующие, некоторые из которых вам уже знакомы:
fs.access() : проверяет существование файла и возможность доступа к нему с учётом разрешений.
fs.appendFile() : присоединяет данные к файлу. Если файл не существует - он будет создан.
fs.chmod() : изменяет разрешения для заданного файла. Похожие методы: fs.lchmod() , fs.fchmod() .
fs.chown() : изменяет владельца и группу для заданного файла. Похожие методы: fs.fchown() , fs.lchown() .
fs.close() : закрывает дескриптор файла.
fs.copyFile() : копирует файл.
fs.createReadStream() : создаёт поток чтения файла.
fs.createWriteStream() : создаёт поток записи файла.
fs.link() : создаёт новую жёсткую ссылку на файл.
fs.mkdir() : создаёт новую директорию.
fs.mkdtemp() : создаёт временную директорию.
fs.open() : открывает файл.
fs.readdir() : читает содержимое директории.
fs.readFile() : считывает содержимое файла. Похожий метод: fs.read() .
fs.readlink() : считывает значение символической ссылки.
fs.realpath() : разрешает относительный путь к файлу, построенный с использованием символов. и.. , в полный путь.
fs.rename() : переименовывает файл или папку.
fs.rmdir() : удаляет папку.
fs.stat() : возвращает сведения о файле. Похожие методы: fs.fstat() , fs.lstat() .
fs.symlink() : создаёт новую символическую ссылку на файл.
fs.truncate() : обрезает файл до заданной длины. Похожий метод: fs.ftruncate() .
fs.unlink() : удаляет файл или символическую ссылку.
fs.unwatchFile() : отключает наблюдение за изменениями файла.
fs.utimes() : изменяет временную отметку файла. Похожий метод: fs.futimes() .
fs.watchFile() : включает наблюдение за изменениями файла. Похожий метод: fs.watch() .
fs.writeFile() : записывает данные в файл. Похожий метод: fs.write() .
Интересной особенностью модуля fs является тот факт, что все его методы, по умолчанию, являются асинхронными, но существуют и их синхронные версии, имена которых получаются путём добавления слова Sync к именам асинхронных методов.
Например:
fs.rename()
fs.renameSync()
fs.write()
fs.writeSync()
Использование синхронных методов серьёзно влияет на то, как работает программа.
В Node.js 10 имеется экспериментальная поддержка этих API , основанных на промисах.
Исследуем метод fs.rename() . Вот асинхронная версия этого метода, использующая коллбэки:
Const fs = require("fs")
fs.rename("before.json", "after.json", (err) => {
if (err) {
return console.error(err)
}
//готово
})
При использовании его синхронной версии для обработки ошибок используется конструкция try/catch:
Const fs = require("fs")
try {
fs.renameSync("before.json", "after.json")
//готово
} catch (err) {
console.error(err)
}
Основное различие между этими вариантами использования данного метода заключается в том, что во втором случае выполнение скрипта будет заблокировано до завершения файловой операции.
Модуль path
Модуль path, о некоторых возможностях которого мы тоже уже говорили, содержит множество полезных инструментов, позволяющих взаимодействовать с файловой системой. Как уже было сказано, устанавливать его не нужно, так как он является частью Node.js. Для того чтобы пользоваться им, его достаточно подключить:
Const path = require("path")
Свойство path.sep этого модуля предоставляет символ, использующийся для разделения сегментов пути (в Windows и / в Linux и macOS), а свойство path.delimiter даёт символ, используемый для отделения друг от друга нескольких путей (; в Windows и: в Linux и macOS).
Рассмотрим и проиллюстрируем примерами некоторые методы модуля path .
▍path.basename()
Возвращает последний фрагмент пути. Передав второй параметр этому методу можно убрать расширение файла.
Require("path").basename("/test/something") //something
require("path").basename("/test/something.txt") //something.txt
require("path").basename("/test/something.txt", ".txt") //something
▍path.dirname()
Возвращает ту часть пути, которая представляет имя директории:
Require("path").dirname("/test/something") // /test
require("path").dirname("/test/something/file.txt") // /test/something
▍path.extname()
Возвращает ту часть пути, которая представляет расширение файла:
require("path").dirname("/test/something") // ""
require("path").dirname("/test/something/file.txt") // ".txt"
▍path.isAbsolute()
Возвращает истинное значение если путь является абсолютным:
Require("path").isAbsolute("/test/something") // true
require("path").isAbsolute("./test/something") // false
▍path.join()
Соединяет несколько частей пути:
Const name = "flavio"
require("path").join("/", "users", name, "notes.txt") //"/users/flavio/notes.txt"
▍path.normalize()
Пытается выяснить реальный путь на основе пути, который содержит символы, использующиеся при построении относительных путей вроде. , .. и // :
Require("path").normalize("/users/flavio/..//test.txt") ///users/test.txt
▍path.parse()
Преобразует путь в объект, свойства которого представляют отдельные части пути:
root: корневая директория.
dir: путь к файлу, начиная от корневой директории
base: имя файла и расширение.
name: имя файла.
ext: расширение файла.
Вот пример использования этого метода:
Require("path").parse("/users/test.txt")
В результате его работы получается такой объект:
{
root: "/",
dir: "/users",
base: "test.txt",
ext: ".txt",
name: "test"
}
▍path.relative()
Принимает, в качестве аргументов, 2 пути. Возвращает относительный путь из первого пути ко второму, основываясь на текущей рабочей директории:
Require("path").relative("/Users/flavio", "/Users/flavio/test.txt") //"test.txt"
require("path").relative("/Users/flavio", "/Users/flavio/something/test.txt") //"something/test.txt"
▍path.resolve()
Находит абсолютный путь на основе переданного ему относительного пути:
Path.resolve("flavio.txt")
//"/Users/flavio/flavio.txt" при запуске из моей домашней папки.
Итоги
Сегодня мы рассмотрели модули Node.js fs и path , которые используются для работы с файловой системой. В следующей части этой серии, на которой она завершается, мы обсудим модули os , events , http , поговорим о работе с потоками и с системами управления базами данных в Node.js.
Уважаемые читатели!
Какими npm-пакетами вы пользуетесь при работе с файловой системой в Node.js?
Сегодня, в девятой части перевода руководства по Node.js, мы поговорим о работе с файлами. В частности, речь пойдёт о модулях fs и path - о файловых дескрипторах, о путях к файлам, о получении информации о файлах, об их чтении и записи, о работе с директориями.
Работа с файловыми дескрипторами в Node.js
Прежде чем вы сможете взаимодействовать с файлами, находящимися в файловой системе вашего сервера, вам необходимо получить дескриптор файла.Дескриптор можно получить, воспользовавшись для открытия файла асинхронным методом open() из модуля fs:
Const fs = require("fs")
fs.open("/Users/flavio/test.txt", "r", (err, fd) => {
//fd - это дескриптор файла
})
Обратите внимание на второй параметр, r , использованный при вызове метода fs.open() . Это - флаг, который сообщает системе о том, что файл открывают для чтения. Вот ещё некоторые флаги, которые часто используются при работе с этим и некоторыми другими методами:
r+ - открыть файл для чтения и для записи.
w+ - открыть файл для чтения и для записи, установив указатель потока в начало файла. Если файл не существует - он создаётся.
a - открыть файл для записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
a+ - открыть файл для чтения и записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
Файлы можно открывать и пользуясь синхронным методом fs.openSync() , который, вместо того, чтобы предоставить дескриптор файла в коллбэке, возвращает его:Const fs = require("fs")
try {
const fd = fs.openSync("/Users/flavio/test.txt", "r")
} catch (err) {
console.error(err)
}
После получения дескриптора любым из вышеописанных способов вы можете производить с ним необходимые операции.
Данные о файлах
С каждым файлом связан набор данных о нём, исследовать эти данные можно средствами Node.js. В частности, сделать это можно, используя метод stat() из модуля fs .Вызывают этот метод, передавая ему путь к файлу, и, после того, как Node.js получит необходимые сведения о файле, он вызовет коллбэк, переданный методу stat() . Вот как это выглядит:
Const fs = require("fs")
fs.stat("/Users/flavio/test.txt", (err, stats) => {
if (err) {
console.error(err)
return
}
//сведения о файле содержатся в аргументе `stats`
})
В Node.js имеется возможность синхронного получения сведений о файлах. При таком подходе главный поток блокируется до получения свойств файла:
Const fs = require("fs")
try {
const stats = fs.statSync ("/Users/flavio/test.txt")
} catch (err) {
console.error(err)
}
Информация о файле попадёт в константу stats . Что это за информация? На самом деле, соответствующий объект предоставляет нам большое количество полезных свойств и методов:
Методы.isFile() и.isDirectory() позволяют, соответственно, узнать, является ли исследуемый файл обычным файлом или директорией.
Метод.isSymbolicLink() позволяет узнать, является ли файл символической ссылкой.
Размер файла можно узнать, воспользовавшись свойством.size .
Тут имеются и другие методы, но эти - самые употребимые. Вот как ими пользоваться:Const fs = require("fs")
fs.stat("/Users/flavio/test.txt", (err, stats) => {
if (err) {
console.error(err)
return
}
stats.isFile() //true
stats.isDirectory() //false
stats.isSymbolicLink() //false
stats.size //1024000 //= 1MB
})
Пути к файлам в Node.js и модуль path
Путь к файлу - это адрес того места в файловой системе, где он расположен.В Linux и macOS путь может выглядеть так:
/users/flavio/file.txt
В Windows пути выглядят немного иначе:
C:\users\flavio\file.txt
На различия в форматах записи путей при использовании разных операционных систем следует обращать внимание, учитывая операционную систему, используемую для развёртывания Node.js-сервера.
В Node.js есть стандартный модуль path , предназначенный для работы с путями к файлам. Перед использованием этого модуля в программе его надо подключить:
▍Получение информации о пути к файлу
Если у вас есть путь к файлу, то, используя возможности модуля path , вы можете, в удобном для восприятия и дальнейшей обработки виде, узнать подробности об этом пути. Выглядит это так:Const notes = "/users/flavio/notes.txt"
path.dirname(notes) // /users/flavio
path.basename(notes) // notes.txt
path.extname(notes) // .txt
Здесь, в строке notes , хранится путь к файлу. Для разбора пути использованы следующие методы модуля path:
dirname() - возвращает родительскую директорию файла.
basename() - возвращает имя файла.
extname() - возвращает расширение файла.
Узнать имя файла без расширения можно, вызвав метод.basename() и передав ему второй аргумент, представляющий расширение:Path.basename(notes, path.extname(notes)) //notes
▍Работа с путями к файлам
Несколько частей пути можно объединить, используя метод path.join() :Const name = "flavio"
path.join("/", "users", name, "notes.txt") //"/users/flavio/notes.txt"
Найти абсолютный путь к файлу на основе относительного пути к нему можно с использованием метода path.resolve() :
Path.resolve("flavio.txt")
//"/Users/flavio/flavio.txt" при запуске из моей домашней папки
В данном случае Node.js просто добавляет /flavio.txt к пути, ведущем к текущей рабочей директории. Если при вызове этого метода передать ещё один параметр, представляющий путь к папке, метод использует его в качестве базы для определения абсолютного пути:
Path.resolve("tmp", "flavio.txt")
// "/Users/flavio/tmp/flavio.txt" при запуске из моей домашней папки
Если путь, переданный в качестве первого параметра, начинается с косой черты - это означает, что он представляет собой абсолютный путь.
Path.resolve("/etc", "flavio.txt")
// "/etc/flavio.txt"
Вот ещё один полезный метод - path.normalize() . Он позволяет найти реальный путь к файлу, используя путь, в котором содержатся спецификаторы относительного пути вроде точки (.), двух точек (..), или двух косых черт:
Path.normalize("/users/flavio/..//test.txt")
// /users/test.txt
Методы resolve() и normalize() не проверяют существование директории. Они просто находят путь, основываясь на переданным им данным.
Чтение файлов в Node.js
Самый простой способ чтения файлов в Node.js заключается в использовании метода fs.readFile() с передачей ему пути к файлу и коллбэка, который будет вызван с передачей ему данных файла (или объекта ошибки):Fs.readFile("/Users/flavio/test.txt", (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
Если надо, можно воспользоваться синхронной версией этого метода - fs.readFileSync() :
Const fs = require("fs")
try {
const data = fs.readFileSync("/Users/flavio/test.txt")
console.log(data)
} catch (err) {
console.error(err)
}
По умолчанию при чтении файлов используется кодировка utf8 , но кодировку можно задать и самостоятельно, передав методу соответствующий параметр.
Методы fs.readFile() и fs.readFileSync() считывают в память всё содержимое файла. Это означает, что работа с большими файлами с применением этих методов серьёзно отразится на потреблении памяти вашим приложением и окажет влияние на его производительность. Если с такими файлами нужно работать, лучше всего воспользоваться потоками.
Запись файлов в Node.js
В Node.js легче всего записывать файлы с использованием метода fs.writeFile() :Const fs = require("fs")
const content = "Some content!"
fs.writeFile("/Users/flavio/test.txt", content, (err) => {
if (err) {
console.error(err)
return
}
//файл записан успешно
})
Есть и синхронная версия того же метода - fs.writeFileSync() :
Const fs = require("fs")
const content = "Some content!"
try {
const data = fs.writeFileSync("/Users/flavio/test.txt", content)
//файл записан успешно
} catch (err) {
console.error(err)
}
Эти методы, по умолчанию, заменяют содержимое существующих файлов. Изменить их стандартное поведение можно, воспользовавшись соответствующим флагом:
Fs.writeFile("/Users/flavio/test.txt", content, { flag: "a+" }, (err) => {})
Тут могут использоваться флаги, которые мы уже перечисляли в разделе, посвящённом дескрипторам. Подробности о флагах можно узнать .
Присоединение данных к файлу
Метод fs.appendFile() (и его синхронную версию - fs.appendFileSync()) удобно использовать для присоединения данных к концу файла:Const content = "Some content!"
fs.appendFile("file.log", content, (err) => {
if (err) {
console.error(err)
return
}
//готово!
})
Об использовании потоков
Выше мы описывали методы, которые, выполняя запись в файл, пишут в него весь объём переданных им данных, после чего, если используются их синхронные версии, возвращают управление программе, а если применяются асинхронные версии - вызывают коллбэки. Если вас такое состояние дел не устраивает - лучше будет воспользоваться потоками.Работа с директориями в Node.js
Модуль fs предоставляет в распоряжение разработчика много удобных методов, которые можно использовать для работы с директориями.▍Проверка существования папки
Для того чтобы проверить, существует ли директория и может ли Node.js получить к ней доступ, учитывая разрешения, можно использовать метод fs.access() .▍Создание новой папки
Для того чтобы создавать новые папки, можно воспользоваться методами fs.mkdir() и fs.mkdirSync() :Const fs = require("fs")
const folderName = "/Users/flavio/test"
try {
if (!fs.existsSync(dir)){
fs.mkdirSync(dir)
}
} catch (err) {
console.error(err)
}
▍Чтение содержимого папки
Для того чтобы прочесть содержимое папки, можно воспользоваться методами fs.readdir() и fs.readdirSync() . В этом примере осуществляется чтение содержимого папки - то есть - сведений о том, какие файлы и поддиректории в ней имеются, и возврат их относительных путей:Const fs = require("fs")
const path = require("path")
const folderPath = "/Users/flavio"
fs.readdirSync(folderPath)
Вот так можно получить полный путь к файлу:
Fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)
}
Результаты можно отфильтровать для того, чтобы получить только файлы и исключить из вывода директории:
Const isFile = fileName => {
return fs.lstatSync(fileName).isFile()
}
fs.readdirSync(folderPath).map(fileName => {
return path.join(folderPath, fileName)).filter(isFile)
}
▍Переименование папки
Для переименования папки можно воспользоваться методами fs.rename() и fs.renameSync() . Первый параметр - это текущий путь к папке, второй - новый:Const fs = require("fs")
fs.rename("/Users/flavio", "/Users/roger", (err) => {
if (err) {
console.error(err)
return
}
//готово
})
Переименовать папку можно и с помощью синхронного метода fs.renameSync() :
Const fs = require("fs")
try {
fs.renameSync("/Users/flavio", "/Users/roger")
} catch (err) {
console.error(err)
}
▍Удаление папки
Для того чтобы удалить папку, можно воспользоваться методами fs.rmdir() или fs.rmdirSync() . Надо отметить, что удаление папки, в которой что-то есть, задача несколько более сложная, чем удаление пустой папки. Если вам нужно удалять такие папки, воспользуйтесь пакетом fs-extra , который весьма популярен и хорошо поддерживается. Он представляет собой замену модуля fs , расширяющую его возможности.Метод remove() из пакета fs-extra умеет удалять папки, в которых уже что-то есть.
Установить этот модуль можно так:
Npm install fs-extra
Вот пример его использования:
Const fs = require("fs-extra")
const folder = "/Users/flavio"
fs.remove(folder, err => {
console.error(err)
})
Его методами можно пользоваться в виде промисов:
Fs.remove(folder).then(() => {
//готово
}).catch(err => {
console.error(err)
})
Допустимо и применение конструкции async/await:
Async function removeFolder(folder) {
try {
await fs.remove(folder)
//готово
} catch (err) {
console.error(err)
}
}
const folder = "/Users/flavio"
removeFolder(folder)
Модуль fs
Выше мы уже сталкивались с некоторыми методами модуля fs , применяемыми при работе с файловой системой. На самом деле, он содержит ещё много полезного. Напомним, что он не нуждается в установке, для того, чтобы воспользоваться им в программе, его достаточно подключить:Const fs = require("fs")
После этого у вас будет доступ к его методам, среди которых отметим следующие, некоторые из которых вам уже знакомы:
fs.access() : проверяет существование файла и возможность доступа к нему с учётом разрешений.
fs.appendFile() : присоединяет данные к файлу. Если файл не существует - он будет создан.
fs.chmod() : изменяет разрешения для заданного файла. Похожие методы: fs.lchmod() , fs.fchmod() .
fs.chown() : изменяет владельца и группу для заданного файла. Похожие методы: fs.fchown() , fs.lchown() .
fs.close() : закрывает дескриптор файла.
fs.copyFile() : копирует файл.
fs.createReadStream() : создаёт поток чтения файла.
fs.createWriteStream() : создаёт поток записи файла.
fs.link() : создаёт новую жёсткую ссылку на файл.
fs.mkdir() : создаёт новую директорию.
fs.mkdtemp() : создаёт временную директорию.
fs.open() : открывает файл.
fs.readdir() : читает содержимое директории.
fs.readFile() : считывает содержимое файла. Похожий метод: fs.read() .
fs.readlink() : считывает значение символической ссылки.
fs.realpath() : разрешает относительный путь к файлу, построенный с использованием символов. и.. , в полный путь.
fs.rename() : переименовывает файл или папку.
fs.rmdir() : удаляет папку.
fs.stat() : возвращает сведения о файле. Похожие методы: fs.fstat() , fs.lstat() .
fs.symlink() : создаёт новую символическую ссылку на файл.
fs.truncate() : обрезает файл до заданной длины. Похожий метод: fs.ftruncate() .
fs.unlink() : удаляет файл или символическую ссылку.
fs.unwatchFile() : отключает наблюдение за изменениями файла.
fs.utimes() : изменяет временную отметку файла. Похожий метод: fs.futimes() .
fs.watchFile() : включает наблюдение за изменениями файла. Похожий метод: fs.watch() .
fs.writeFile() : записывает данные в файл. Похожий метод: fs.write() .
Интересной особенностью модуля fs является тот факт, что все его методы, по умолчанию, являются асинхронными, но существуют и их синхронные версии, имена которых получаются путём добавления слова Sync к именам асинхронных методов.Например:
fs.rename()
fs.renameSync()
fs.write()
fs.writeSync()
Использование синхронных методов серьёзно влияет на то, как работает программа.В Node.js 10 имеется экспериментальная поддержка этих API , основанных на промисах.
Исследуем метод fs.rename() . Вот асинхронная версия этого метода, использующая коллбэки:
Const fs = require("fs")
fs.rename("before.json", "after.json", (err) => {
if (err) {
return console.error(err)
}
//готово
})
При использовании его синхронной версии для обработки ошибок используется конструкция try/catch:
Const fs = require("fs")
try {
fs.renameSync("before.json", "after.json")
//готово
} catch (err) {
console.error(err)
}
Основное различие между этими вариантами использования данного метода заключается в том, что во втором случае выполнение скрипта будет заблокировано до завершения файловой операции.
Модуль path
Модуль path, о некоторых возможностях которого мы тоже уже говорили, содержит множество полезных инструментов, позволяющих взаимодействовать с файловой системой. Как уже было сказано, устанавливать его не нужно, так как он является частью Node.js. Для того чтобы пользоваться им, его достаточно подключить:Const path = require("path")
Свойство path.sep этого модуля предоставляет символ, использующийся для разделения сегментов пути (\ в Windows и / в Linux и macOS), а свойство path.delimiter даёт символ, используемый для отделения друг от друга нескольких путей (; в Windows и: в Linux и macOS).
Рассмотрим и проиллюстрируем примерами некоторые методы модуля path .
▍path.basename()
Возвращает последний фрагмент пути. Передав второй параметр этому методу можно убрать расширение файла.Require("path").basename("/test/something") //something
require("path").basename("/test/something.txt") //something.txt
require("path").basename("/test/something.txt", ".txt") //something
▍path.dirname()
Возвращает ту часть пути, которая представляет имя директории:Require("path").dirname("/test/something") // /test
require("path").dirname("/test/something/file.txt") // /test/something
▍path.extname()
Возвращает ту часть пути, которая представляет расширение файла:Require("path").extname("/test/something") // ""
require("path").extname("/test/something/file.txt") // ".txt"
▍path.isAbsolute()
Возвращает истинное значение если путь является абсолютным:Require("path").isAbsolute("/test/something") // true
require("path").isAbsolute("./test/something") // false
▍path.join()
Соединяет несколько частей пути:Const name = "flavio"
require("path").join("/", "users", name, "notes.txt") //"/users/flavio/notes.txt"
▍path.normalize()
Пытается выяснить реальный путь на основе пути, который содержит символы, использующиеся при построении относительных путей вроде. , .. и // :Require("path").normalize("/users/flavio/..//test.txt") ///users/test.txt
▍path.parse()
Преобразует путь в объект, свойства которого представляют отдельные части пути:root: корневая директория.
dir: путь к файлу, начиная от корневой директории
base: имя файла и расширение.
name: имя файла.
ext: расширение файла.
Вот пример использования этого метода:Require("path").parse("/users/test.txt")
В результате его работы получается такой объект:
{
root: "/",
dir: "/users",
base: "test.txt",
ext: ".txt",
name: "test"
}
▍path.relative()
Принимает, в качестве аргументов, 2 пути. Возвращает относительный путь из первого пути ко второму, основываясь на текущей рабочей директории:Require("path").relative("/Users/flavio", "/Users/flavio/test.txt") //"test.txt"
require("path").relative("/Users/flavio", "/Users/flavio/something/test.txt") //"something/test.txt"
▍path.resolve()
Находит абсолютный путь на основе переданного ему относительного пути:Path.resolve("flavio.txt")
//"/Users/flavio/flavio.txt" при запуске из моей домашней папки.
Итоги
Сегодня мы рассмотрели модули Node.js fs и path , которые используются для работы с файловой системой. В следующей части этой серии, на которой она завершается, мы обсудим модули os , events , http , поговорим о работе с потоками и с системами управления базами данных в Node.js.Уважаемые читатели!
Какими npm-пакетами вы пользуетесь при работе с файловой системой в Node.js?
Всем привет! В этой статье мы рассмотрим, как записывать и читать файлы в NodeJS.
Для этого нам потребуется использовать модуль FS(file system). var fs =require(`fs`)-
Для демонстрации считывания содержимого файлов давайте создадим файлик с названием readme.txt.
Видео: node.js » модуль fs » запись в файл
// содержимое файла readme.txt
Здеськакое-нибудьсодержимоефайла
var text = fs.readFileSync(`readme.txt`,`utf8`)-
console.log(text)-
Мы используем метод, в который передаем первым параметром имя файла, а вторым – кодировку. Как понятно из названия, этот метод является синхронным. Это значит, что весь код, который идет ниже, выполнится только тогда, когда весь файл будет прочитан. Дальше мы просто записываем полученные данные в переменную, которую потом выводим на экран.
Видео: Node.js — создание Excel файла по шаблону
Теперь давайте попробуем считанное нами содержание файла записать в новый файл.
Для этого напишем следующее:
fs.writeFileSync(`writeme.txt`, text)-
Теперь после запуска кода вы увидите, что создался новый файлик с названием writeme.txt, в котором будет содержимое, записанное в переменную text из файла readme.txt.
Видео: Основы Node.JS. 2. Работа с файлами
Давайте рассмотрим, как использовать методы асинхронно.
Например, считаем файлик readme.txt:
console.log(data)-
})-
console.log(`выведется раньше, чем данные из файла`)-
Использование почти такое же, но теперь мы также третьим параметром передаем функцию, где в качестве аргументов первым идет ошибка, а вторым содержимое файла, которое мы потом и выводим.
Ниже я написал еще один вывод текста, чтобы показать вам, что метод действительно асинхронный, поэтому, пока идет считывание файла, выполнится код ниже, а только потом выведется текст из файлика.
Видео: Работа с файлами, модуль fs
Теперь давайте снова считаем содержимое файла readme.txt и запишем его в файл writeme.txt, но только теперь асинхронно.
fs.readFile(`readme.txt`,`utf8`,function(error, data){
fs.writeFile(`writeme.txt`, data)-
})-
А на этом у меня сегодня все. Спасибо за внимание!
(Пока оценок нет)
Если вы хотите сделать веб-сервер на Node.js или просто какое-то приложение, тогда вам нужно уметь читать файлы.
Node предоставляет библиотеку для работы с файловой системой. К примеру, для чтения файлов.
Асинхронное чтение файла (неблокирующее)
"Нормальный" способ чтения файлов в Node.js это чтение асинхронным способом. Это значит, что вы вызываете команду чтения файла и передаете callback, который будет вызван при завершении чтения. Это позволяет работать с несколькими запросами чтения параллельно.
Для этого мы можем использовать метод readFile из класса fs
.
examples/node/non-blocking-read-file.js
Var fs = require("fs");
fs.readFile("DATA", "utf8", function(err, contents) {
console.log(contents);
});
console.log("after calling readFile");
Для начала мы загружаем класс fs
с помощью команды require
. Затем вызываем метод readFile
, который получает 3 параметра: имя файла ("DATA" в нашем случае), кодировку файла ("utf8" в примере) и функцию. Эта функция будет вызывана, когда завершится операция чтения файла. Функция получит два параметра. Первый - информация о каких-либо ошибках, второй - содержимое файла.
Как только программа будет запущена, Node начнет читать файл в фоновом режиме, но продолжит выполнение. Таким образом, сначала будет выполнен вызов console.log("after calling readFile");
, который выведет этот текст в консоль.
Затем, когда содержимое файла будет загружено в память, Node вызовет функцию, которую мы передали в метод readFile
, и она выведет в консоль содержимое файла.
Синхронное чтение файла (блокирующее)
Люди, пришедшие из других языков программирования (из большинства), считают синхронное чтение файлов более очевидным. Я не знаю в какой ситуации вы захотите использовать синхронные операции в Node.js, но я вижу, что много асинхронных функций имеют синхронный вариант, наверное, этим кто-то пользуется.
Для чтения файлов вы можете использовать метод readFileSync из класса fs
:
examples/node/blocking-read-file.js
Var fs = require("fs");
var contents = fs.readFileSync("DATA", "utf8");
console.log(contents);
Последнее обновление: 23.05.2019
Для работы с файлами в Node.js предназначен модуль . Рассмотрим, как с ним работать.
Чтение из файла
Допустим, в одной папке с файлом приложения app.js расположен текстовый файл hello.txt
с простейшим текстом, например:
Hello Node JS!
Для чтения файла в синхронном варианте применяется функция fs.readFileSync()
:
Let fileContent = fs.readFileSync("hello.txt", "utf8");
В метод передается путь к файлу относительно файла приложения app.js, а в качестве второго параметра указывается кодировка для получения текстового содержимого файла.
На выходе получаем считанный текст.
Для асинхронного чтения файла применяется функция fs.readFile
:
Fs.readFile("hello.txt", "utf8", function(error,data){ });
Первый и второй параметр функции опять же соответственно путь к файлу и кодировка. А в качестве третьего параметра передается функция обратного вызова,
которая выполняется после завершения чтения. Первый параметр этой функции хранит информацию об ошибке при наличии, а второй - собственно считанные данные.
Для чтения файла определим в файле app.js следующий код:
Const fs = require("fs");
// асинхронное чтение
fs.readFile("hello.txt", "utf8",
function(error,data){
console.log("Асинхронное чтение файла");
if(error) throw error; // если возникла ошибка
console.log(data); // выводим считанные данные
});
// синхронное чтение
console.log("Синхронное чтение файла")
let fileContent = fs.readFileSync("hello.txt", "utf8");
console.log(fileContent);
И здесь стоит обратить внимание, что несмотря на то, что функция fs.readFile() вызывается первой, но так как она асинхронная, она не блокирует
поток выполнения, поэтому ее результат выводится в самом конце.
Запись файла
Для записи файла в синхронном варианте используется функция fs.writeFileSync()
, которая в качестве параметра принимает путь к файлу
и записываемые данные:
Fs.writeFileSync("hello.txt", "Привет ми ми ми!")
Также для записи файла можно использовать асинхронную функцию fs.writeFile()
, которая принимает те же параметры:
Fs.writeFile("hello.txt", "Привет МИГ-29!")
В качестве вспомогательного параметра в функцию может передаваться функция обратного вызова, которая выполняется после завершения записи:
Const fs = require("fs");
fs.writeFile("hello.txt", "Hello мир!", function(error){
if(error) throw error; // если возникла ошибка
console.log("Асинхронная запись файла завершена. Содержимое файла:");
let data = fs.readFileSync("hello.txt", "utf8");
console.log(data); // выводим считанные данные
});
Следует отметить, что эти методы полностью перезаписывают файл. Если надо дозаписать файл, то применяются методы fs.appendFile()/fs.appendFileSync()
:
Const fs = require("fs");
fs.appendFileSync("hello.txt", "Привет ми ми ми!");
fs.appendFile("hello.txt", "Привет МИД!", function(error){
if(error) throw error; // если возникла ошибка
console.log("Запись файла завершена. Содержимое файла:");
let data = fs.readFileSync("hello.txt", "utf8");
console.log(data); // выводим считанные данные
});
Удаление файла
Для удаления файла в синхронном варианте используется функция fs.unlinkSync()
, которая в качестве параметра принимает путь к удаляемому файлу:
Fs.unlinkSync("hello.txt")
Также для удаления файла можно использовать асинхронную функцию fs.unlink()
, которая принимает путь к файлу и функцию, вызываемую при завершении удаления:
Fs.unlink("hello.txt", (err) => {
if (err) console.log(err); // если возникла ошибка
else console.log("hello.txt was deleted");
});