Главная » Вирусы » Node js запись в несуществующий файл. Nodejs
Node js запись в несуществующий файл. Nodejs
Всем привет! В этой статье мы рассмотрим, как записывать и читать файлы в NodeJS
.
Платформа NodeJS
позволяет записывать и читать файлы в операционной системе. Для этого нам потребуется использовать модуль FS
(file system
).
Var fs = require("fs");
Для демонстрации считывания содержимого файлов давайте создадим файлик с названием readme.txt
.
// содержимое файла readme.txt
Здесь какое-нибудь содержимое файла
Var text = fs.readFileSync("readme.txt", "utf8");
console.log(text);
Мы используем метод, в который передаем первым параметром имя файла, а вторым – кодировку. Как понятно из названия, этот метод является синхронным. Это значит, что весь код, который идет ниже, выполнится только тогда, когда весь файл будет прочитан. Дальше мы просто записываем полученные данные в переменную, которую потом выводим на экран.
Теперь давайте попробуем считанное нами содержание файла записать в новый файл. Для этого напишем следующее:
Fs.writeFileSync("writeme.txt", text);
Теперь после запуска кода вы увидите, что создался новый файлик с названием writeme.txt
, в котором будет содержимое, записанное в переменную text
из файла readme.txt
.
Давайте рассмотрим, как использовать методы асинхронно. Например, считаем файлик readme.txt
:
console.log(data);
});
Console.log("выведется раньше, чем данные из файла");
Использование почти такое же, но теперь мы также третьим параметром передаем функцию, где в качестве аргументов первым идет ошибка, а вторым содержимое файла, которое мы потом и выводим. Ниже я написал еще один вывод текста, чтобы показать вам, что метод действительно асинхронный, поэтому, пока идет считывание файла, выполнится код ниже, а только потом выведется текст из файлика.
Теперь давайте снова считаем содержимое файла readme.txt
и запишем его в файл writeme.txt
, но только теперь асинхронно.
А на этом у меня сегодня все. Спасибо за внимание!
Операции с файлами языку JavaScript не в новинку — в JScript, встроенном в Windows, доступен полный набор функций для работы с диском. Node, в силу своей асинхронной природы, несколько усложняет эти в общем то тривиальные задачи.
Сразу хочу предупредить об одной возможной ошибке. Если Вы, как и я, запускаете Node в виртуальной машине из общей папки, помните — VM в эту папку писать не может. Попытки создать или дополнить файлы в ней закончатся только Error: Permission denied
Открытие файла
Обращение к файлам на диске — операция небыстрая. Она в среднем в десятки тысяч раз дольше чем обращение к оперативной памяти. Поэтому, большинство операций с файлами асинхронные. Все операции с файловой системой собраны во встроенном модуле fs
, стало быть начнём с его подключения.
Var fs = require("fs"),
sys = require("sys");
Модуль sys
нам нужен для вывода информации в консоль. В последующих примерах я эти строки буду опускать, чтобы не повторяться.
Путь
к файлу. Относительно запущенного скрипта либо абсолютный.
Флаг
— режим доступа к файлу. Может принимать следующие значения:
r — только чтение, указатель в начале файла
r+ — чтение и запись, указатель в начале файла
w — только запись, указатель в начале файла
w+ — запись и чтение, указатель в начале файла
a — запись, указатель в конце файла
a+ — запись и чтение, указатель в конце файла
Режим доступа
используется если открываемый файл не существует. В таком случае будет создан новый пустой файл с заданным режимом. Нотация стандартная для UNIX — например 0664
Обработчик
— функция, которая будет выполнена при открытии/создании файла. В качестве аргументов передаются флаг ошибки и дескриптор файла
Например:
Fs.open("readme.txt", "r+", 0644, function(err, file_handle) {
if (!err) {
// Операции с открытым файлом
} else {
// Обработка ошибок
}
});
Данные
, которые мы записываем. Объекты здесь будут приведены к строковому типу.
Позиция
, с которой начинается запись. Null означает запись с текущей позиции.
Кодировка
, в которой будут записаны данные. Может быть «ascii
«, «utf8
» и «raw
«
Обработчик
— функция, которая будет выполнена после записи. Аргументы — флаг ошибки и количество записанных байт
Расширим предыдущий пример записью строки 🙂
Fs.open("readme.txt", "a", 0644, function(err, file_handle) {
if (!err) {
// Записываем в конец файла readme.txt фразу "Copyrighted by Me"
// при открытии в режиме "a" указатель уже в конце файла, и мы передаём null
// в качестве позиции
fs.write(file_handle, "Copyrighted by Me", null, "ascii", function(err, written) {
if (!err) {
// Всё прошло хорошо
} else {
// Произошла ошибка при записи
}
});
} else {
// Обработка ошибок при открытии
}
});
Позиция
, с которой начинаем читать. Null — с текущей позиции
Кодировка
, в которой читаются данные. Может быть «ascii
«, «utf8
» и «raw
«. Здесь лучше не ошибаться)
Обработчик
— функция, которая будет выполнена после чтения. Аргументы — флаг ошибки,данные, количество прочитанных байт
Чтение из файла — совсем несложный процесс:
Fs.open("readme.txt", "r", 0644, function(err, file_handle) {
if (!err) {
// Читаем 10 килобайт с начала файла, в ascii
fs.read(file_handle, 10000, null, "ascii", function(err, data) {
if (!err) {
// Всё прошло хорошо, выводим прочитанное в консоль
sys.puts(data);
} else {
// Произошла ошибка при чтении
}
});
} else {
// Обработка ошибок при открытии файла
}
});
После того как чтение/запись завершены, файл надо закрыть. Node может обслуживать одновременно очень много клиентов, поэтому ресурсы лучше освобождать сразу когда они становятся не нужны.
Fs.open("readme.txt", "r", 0644, function(err, file_handle) {
if (!err) {
// Читаем 10 килобайт с начала файла, в ascii
fs.read(file_handle, 10000, null, "ascii", function(err, data) {
if (!err) {
// Всё прошло хорошо, выводим прочитанное в консоль
sys.puts(data);
fs.close(file_handle);
} else {
// Произошла ошибка при чтении
}
});
} else {
// Обработка ошибок при открытии файла
}
});
Вторым аргументом fs.close может принимать функцию-callback, которой передаётся исключение в случае ошибки.
У всех перечисленных функций есть синхронные варианты. К их названию добавлено Sync и они не принимают последним аргументом функцию-обработчик, а просто возвращают соответствующее значение (или бросают исключение). Обратите внимание, readSync возвращает массив из данных и количества прочитанных байт.
Var file_handle = fs.openSync("readme.txt", "r", 0644);
var data = fs.readSync(file_handle, 10000, null, "ascii");
sys.puts(data);
fs.closeSync(file_handle);
Сегодня, в девятой части перевода руководства по Node.js, мы поговорим о работе с файлами. В частности, речь пойдёт о модулях fs и path - о файловых дескрипторах, о путях к файлам, о получении информации о файлах, об их чтении и записи, о работе с директориями.
Работа с файловыми дескрипторами в Node.js
Прежде чем вы сможете взаимодействовать с файлами, находящимися в файловой системе вашего сервера, вам необходимо получить дескриптор файла.
Дескриптор можно получить, воспользовавшись для открытия файла асинхронным методом open() из модуля fs:
Обратите внимание на второй параметр, r , использованный при вызове метода fs.open() . Это - флаг, который сообщает системе о том, что файл открывают для чтения. Вот ещё некоторые флаги, которые часто используются при работе с этим и некоторыми другими методами:
r+ - открыть файл для чтения и для записи.
w+ - открыть файл для чтения и для записи, установив указатель потока в начало файла. Если файл не существует - он создаётся.
a - открыть файл для записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
a+ - открыть файл для чтения и записи, установив указатель потока в конец файла. Если файл не существует - он создаётся.
Файлы можно открывать и пользуясь синхронным методом fs.openSync() , который, вместо того, чтобы предоставить дескриптор файла в коллбэке, возвращает его:
После получения дескриптора любым из вышеописанных способов вы можете производить с ним необходимые операции.
Данные о файлах
С каждым файлом связан набор данных о нём, исследовать эти данные можно средствами 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 имеется возможность синхронного получения сведений о файлах. При таком подходе главный поток блокируется до получения свойств файла:
Информация о файле попадёт в константу stats . Что это за информация? На самом деле, соответствующий объект предоставляет нам большое количество полезных свойств и методов:
Методы.isFile() и.isDirectory() позволяют, соответственно, узнать, является ли исследуемый файл обычным файлом или директорией.
Метод.isSymbolicLink() позволяет узнать, является ли файл символической ссылкой.
Размер файла можно узнать, воспользовавшись свойством.size .
Тут имеются и другие методы, но эти - самые употребимые. Вот как ими пользоваться:
Путь к файлу - это адрес того места в файловой системе, где он расположен.
В Linux и macOS путь может выглядеть так:
/users/flavio/file.txt
В Windows пути выглядят немного иначе:
C:usersflaviofile.txt
На различия в форматах записи путей при использовании разных операционных систем следует обращать внимание, учитывая операционную систему, используемую для развёртывания Node.js-сервера.
В Node.js есть стандартный модуль path , предназначенный для работы с путями к файлам. Перед использованием этого модуля в программе его надо подключить:
▍Получение информации о пути к файлу
Если у вас есть путь к файлу, то, используя возможности модуля path , вы можете, в удобном для восприятия и дальнейшей обработки виде, узнать подробности об этом пути. Выглядит это так:
Узнать имя файла без расширения можно, вызвав метод.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.normalize() . Он позволяет найти реальный путь к файлу, используя путь, в котором содержатся спецификаторы относительного пути вроде точки (.), двух точек (..), или двух косых черт:
Методы resolve() и normalize() не проверяют существование директории. Они просто находят путь, основываясь на переданным им данным.
Чтение файлов в Node.js
Самый простой способ чтения файлов в Node.js заключается в использовании метода fs.readFile() с передачей ему пути к файлу и коллбэка, который будет вызван с передачей ему данных файла (или объекта ошибки):
По умолчанию при чтении файлов используется кодировка 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)
}
Эти методы, по умолчанию, заменяют содержимое существующих файлов. Изменить их стандартное поведение можно, воспользовавшись соответствующим флагом:
Выше мы описывали методы, которые, выполняя запись в файл, пишут в него весь объём переданных им данных, после чего, если используются их синхронные версии, возвращают управление программе, а если применяются асинхронные версии - вызывают коллбэки. Если вас такое состояние дел не устраивает - лучше будет воспользоваться потоками.
Работа с директориями в Node.js
Модуль fs предоставляет в распоряжение разработчика много удобных методов, которые можно использовать для работы с директориями.
▍Проверка существования папки
Для того чтобы проверить, существует ли директория и может ли Node.js получить к ней доступ, учитывая разрешения, можно использовать метод fs.access() .
▍Создание новой папки
Для того чтобы создавать новые папки, можно воспользоваться методами fs.mkdir() и fs.mkdirSync() :
Для того чтобы прочесть содержимое папки, можно воспользоваться методами fs.readdir() и fs.readdirSync() . В этом примере осуществляется чтение содержимого папки - то есть - сведений о том, какие файлы и поддиректории в ней имеются, и возврат их относительных путей:
Для того чтобы удалить папку, можно воспользоваться методами fs.rmdir() или fs.rmdirSync() . Надо отметить, что удаление папки, в которой что-то есть, задача несколько более сложная, чем удаление пустой папки. Если вам нужно удалять такие папки, воспользуйтесь пакетом fs-extra , который весьма популярен и хорошо поддерживается. Он представляет собой замену модуля fs , расширяющую его возможности.
Метод remove() из пакета fs-extra умеет удалять папки, в которых уже что-то есть.
Выше мы уже сталкивались с некоторыми методами модуля 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.watchFile() : включает наблюдение за изменениями файла. Похожий метод: fs.watch() .
fs.writeFile() : записывает данные в файл. Похожий метод: fs.write() .
Интересной особенностью модуля fs является тот факт, что все его методы, по умолчанию, являются асинхронными, но существуют и их синхронные версии, имена которых получаются путём добавления слова Sync к именам асинхронных методов.
Например:
fs.rename()
fs.renameSync()
fs.write()
fs.writeSync()
Использование синхронных методов серьёзно влияет на то, как работает программа.
В Node.js 10 имеется экспериментальная поддержка этих API , основанных на промисах.
Исследуем метод fs.rename() . Вот асинхронная версия этого метода, использующая коллбэки:
Основное различие между этими вариантами использования данного метода заключается в том, что во втором случае выполнение скрипта будет заблокировано до завершения файловой операции.
Модуль path
Модуль path, о некоторых возможностях которого мы тоже уже говорили, содержит множество полезных инструментов, позволяющих взаимодействовать с файловой системой. Как уже было сказано, устанавливать его не нужно, так как он является частью Node.js. Для того чтобы пользоваться им, его достаточно подключить:
Const path = require("path")
Свойство path.sep этого модуля предоставляет символ, использующийся для разделения сегментов пути (в Windows и / в Linux и macOS), а свойство path.delimiter даёт символ, используемый для отделения друг от друга нескольких путей (; в Windows и: в Linux и macOS).
Рассмотрим и проиллюстрируем примерами некоторые методы модуля path .
▍path.basename()
Возвращает последний фрагмент пути. Передав второй параметр этому методу можно убрать расширение файла.