Войти
Все секреты компьютера для новичка и профессионала
  • Как делать предметы в Minecraft
  • Чит Flux B4 (Киллаура, Аимбот, X-Ray)
  • Почему Теле2 не ловит сеть
  • Win Mobile Крым: обслуживание
  • Установленная игра не запускается
  • Что делать, если не загружается игра на компьютере
  • Node js создать файл. Nodejs. Запись и чтение файлов. Я установил Node, что теперь

    Node js создать файл. Nodejs. Запись и чтение файлов. Я установил Node, что теперь

    Был рассмотрен переход от синхронного кода к асинхронному. Во второй части я рассмотрю переход от побайтового чтения из файла к построчному. Поскольку операция кодирования из одной кодировки в другую довольно тривиальна, я чуть больше расскажу про теоретическую сторону вопроса.

    Часть 2: Как прочитать строку из файла

    Fs.readFile("large.txt", { encoding: "utf8" }, (err, data) => { if (err) throw err; data.split("\n").forEach(line => { doSomethingWithLine(line); }); });

    Он же, пожалуй, самый быстрый. Но он же требует больше всего памяти — от 100% до 200% от размера файла. 200% — это одновременно и самый распространенный случай, так как в памяти кодировка у строки UTF-16 и поэтому размер требуемой памяти умножается на два если файл содержит в основном символы из однобайтного диапазона UTF-8.

    Кроме того, разработчики Node.js не рекомендуют загружать много данных в Node.js процесс (см. What is the memory limit on a node process?) . Сделано это не очень элегантно — даже если физической памяти хватает, то при попытке загрузить файл больше 1Gb бросается исключение:

    This.parent = new SlowBuffer(this.length); ^ RangeError: length > kMaxLength

    Если же файл поменьше, то можно получить и такое:

    FATAL ERROR: CALL_AND_RETRY_0 Allocation failed - process out of memory

    Остается только обрабатывать файл по частям. Для этого нужно его по частям прочитать и Node.js предоставляет для этого минимум 5 способов:

    1. Использовать «старые» потоки — открыть поток и подписаться на событие «data».
    2. Использовать «новые» потоки — подписаться на событие «readable» и использовать метод read().
    3. Создать свой WritableStream и направить в него файловый поток методом «pipe()».
    4. Использовать файловые дескрипторы и набор методов open(), read(), close().
    5. Использовать синхронные варианты — openSync(), readSync(), closeSync().

    Варианты 1-3 являются более элегантными, так как оперируют удобной абстракцией — потоком. Это позволяет рассматривать программу как диаграмму потоков данных (data flow diagram) и при дизайне архитектуры оперировать такими терминами как слияние, разделение и трансформация.

    Также варианты 1 и 2 отличаются возможностью чтения символов из файла. В вариантах 3 и 4 данные из файла записываются в буфер и затем их надо конвертировать в текст.

    // Вариант #1 - "старые" потоки var stream = fs.createReadStream(file, { encoding: "utf8" }); stream.on("data", (_, data) => processData(data)); stream.on("end", done); // Вариант #2 - "новые" потоки var stream = fs.createReadStream(file, { encoding: "utf8" }); stream.on("readable", () => processData(stream.read())); stream.on("end", done); // Вариант #3 - pipe var stream = fs.createReadStream(file, { encoding: "utf8" }); var writeStream = new Writable(); writeStream._write = (chunk, encoding, callback) => { processData(chunk); callback(); }; writeStream.on("end", done); stream.pipe(writeStream); // Вариант #4 - асинхронные методы fs fs.open(file, "r", (err, fd) => { var buffer = new Buffer(1000*1000); (function next() { fs.read(fd, buffer, 0, buffer.length, null, (err, bytesRead, buffer) => { if (bytesRead === 0) { fs.close(fd, done); } else { processData(buffer); next(); } }); }()); });

    Более концептуальным является отличие с точки зрения получения данных из файла. Варианты 1-2 получают следующий фрагмент как только завершается обработчик события текущего фрагмента. В случае асинхронного кода в обработчике последовательность его выполнения непредсказуема:

    Function processData(chunk) { console.log("first") setImmediate(() => { console.log("second"); setImmediate(() => console.log("third")); }); } var stream = fs.createReadStream(file, { encoding: "utf8" }); stream.on("readable", () => processData(stream.read())); ... first third second third first second ...

    Ситуацию можно поправить используя методы pause()/resume().

    Function processData(chunk, done) { console.log("first") setImmediate(() => { console.log("second"); setImmediate(() => { console.log("third"); done(); }); }); } var stream = fs.createReadStream(file, { encoding: "utf8" }); stream.on("readable", () => { stream.pause(); processData(stream.read(), () => stream.resume()); }); ... first second third first second third ...

    В вариантах 3 и 4 следующий фрагмент будет получен только после передачи управления (вариант 3) или запроса (вариант 4).

    Думаю, что информации достаточно для реализации функции createTextReader() из первой части статьи. Из всех вариантов наиболее соответствующим является четвертый, поскольку поток управления у него аналогичен интерфейсу (request-callback).

    Function createTextReader(file, options, done) { var length, encoding, separator; if ("function" === typeof options) { done = options; options = { }; } length = 4 * 1024; encoding = options.encoding || "utf8"; separator = (options.separator || "\n"); fs.open(file, "r", (err, fd) => { var eof, tail, buffer, decoder, lines; if (err) { done(err); return; } eof = false; buffer = new Buffer(length); tail = ""; lines = ; decoder = new StringDecoder(encoding); done(null, { readLine: done => { var line; if (lines.length > 0) { line = lines.shift(); done(null, line); } else if (eof) { done(null, null); } else { (function read() { fs.read(fd, buffer, 0, length, null, function (err, bytesRead, buffer) { var index, position; if (bytesRead === 0) { eof = true; done(null, tail); } else { tail = tail + decoder.write(buffer.slice(0, bytesRead)); index = -1; while (-1 !== (position = tail.indexOf(separator, index))) { lines.push(tail.substring(index, position)); index = position + separator.length; } tail = tail.substring(index); if (lines.length === 0) { read(); } else { line = lines.shift(); done(null, line); } } }); }()); } }, close: done => { fs.close(fd, () => { if (done) { done(err || null); } }); } }); }); }

    Послесловие

    В двух частях этой статьи я постарался изложить все, что мне пригодилось при создании модуля https://github.com/AlexAtNet/async-read-lines . К сожалению, многое осталось за рамками, не на все хватило времени. Так что если нашли ошибку или опечатку — пишите в личные сообщения. Если у вас есть вопросы по теме статьи — буду рад ответить в комментариях. Если увидите баги в модуле — создавайте запрос в github issues . Связаться со мной лично можно через сайт alexatnet.com .

    Успехов в программировании!

    Об авторе: Александр Неткачев — старший разработчик на С# и F#. Поддерживает сайт alexatnet.com , проводит вебинары (Code&Coffe), помогает с кодом начинающим разработчикам (CodeReview4U).

    Если вы хотите сделать веб-сервер на 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);

    Операции с файлами языку JavaScript не в новинку — в JScript, встроенном в Windows, доступен полный набор функций для работы с диском. Node, в силу своей асинхронной природы, несколько усложняет эти в общем то тривиальные задачи.

    Сразу хочу предупредить об одной возможной ошибке. Если Вы, как и я, запускаете Node в виртуальной машине из общей папки, помните — VM в эту папку писать не может. Попытки создать или дополнить файлы в ней закончатся только Error: Permission denied

    Открытие файла

    Обращение к файлам на диске — операция небыстрая. Она в среднем в десятки тысяч раз дольше чем обращение к оперативной памяти. Поэтому, большинство операций с файлами асинхронные. Все операции с файловой системой собраны во встроенном модуле fs , стало быть начнём с его подключения.

    Var fs = require("fs"), sys = require("sys");

    Модуль sys нам нужен для вывода информации в консоль. В последующих примерах я эти строки буду опускать, чтобы не повторяться.

    Открытие файла делается так:

    Fs.open(<путь> , <флаги> , <режим доступа> , <функция-обработчик> )

    • Путь к файлу. Относительно запущенного скрипта либо абсолютный.
    • Флаг — режим доступа к файлу. Может принимать следующие значения:
      • r — только чтение, указатель в начале файла
      • r+ — чтение и запись, указатель в начале файла
      • w — только запись, указатель в начале файла
      • w+ — запись и чтение, указатель в начале файла
      • a — запись, указатель в конце файла
      • a+ — запись и чтение, указатель в конце файла
    • Режим доступа используется если открываемый файл не существует. В таком случае будет создан новый пустой файл с заданным режимом. Нотация стандартная для UNIX — например 0664
    • Обработчик — функция, которая будет выполнена при открытии/создании файла. В качестве аргументов передаются флаг ошибки и дескриптор файла

    Например:

    Fs.open("readme.txt", "r+", 0644, function(err, file_handle) { if (!err) { // Операции с открытым файлом } else { // Обработка ошибок } });

    Запись в файл

    Для записи в файл используется метод fs.write:

    Fs.write(<дескриптор> , <данные> , <позиция> , <кодировка> , <обработчик> )

    • Дескриптор файла, полученный в fs.open .
    • Данные , которые мы записываем. Объекты здесь будут приведены к строковому типу.
    • Позиция , с которой начинается запись. 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 { // Обработка ошибок при открытии } });

    Чтение из файла

    Чтение делается так:

    Fs.read(<дескриптор> , <длина> , <позиция> , <кодировка> , <обработчик> )

    Здесь всё почти так же, как в fs.write .

    • Дескриптор файла, полученный в fs.open
    • Длина данных, которые мы планируем прочитать
    • Позиция , с которой начинаем читать. 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, но большинство из них охватывают либо какие-то конкретные варианты использования, либо темы, применимые уже тогда, когда у вас есть работающий Node.js То тут, то там я вижу комментарии вроде «я скачал Node.js, что теперь?». Статья ответит на этот вопрос и объяснит, как начать с самого начала.

    Что есть Node.js?

    Много путаницы у новичков в Node.js возникает из-за непонимания того, что же на самом деле это такое. И описание на nodejs.org не слишком помогает разобраться.

    Важно понять, что Node - это не веб-сервер. Сам по себе он ничего не делает. Это не Apache. Там нет конфиг-файла, в котором указывается путь до HTML-файлов. Если вам нужен HTTP-сервер, вам нужно написать HTTP-сервер (с помощью встроенных библиотек). Node.js - это просто ещё один способ выполнять код на вашем компьютере. Это просто среда для выполнения JavaScript.

    Установка Node

    Установить Node.js очень просто. Если вы используете Windows или Mac, установочные файлы доступны на странице загрузки .

    Я установил Node, что теперь?

    Сразу после установки вам становится доступна новая команда node . Её можно использовать двумя разными способами. Первый способ - без аргументов. Откроется интерактивная оболочка (REPL: read-eval-print-loop), где вы можете выполнять обычный JavaScript-код.

    $ node > console .log("Hello World" ); Hello World undefined

    В примере выше я написал console.log("Hello World") в оболочке и нажал Enter. Node.js выполнит этот код, и мы увидим сообщение. undefined после него выводится потому, что оболочка отображает возвращаемое значение каждой команды, а console.log ничего не возвращает.

    Кроме того, мы можем передать Node файл с JavaScript для выполнения. Именно так вы и будете практически всегда делать.

    hello.js

    console .log("Hello World" );

    Теперь запустим его в терминале:

    $ node hello.js Hello World

    В этом примере я переместил console.log в файл, который затем передал команде node в качестве аргумента. Node затем запускает JavaScript из этого файла и выводит Hello World .

    Делаем что-нибудь полезное - работа с файлами

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

    example_log.txt

    2013-08-09T13 :50 :33.166Z A 2 2013-08-09T13 :51 :33.166Z B 1 2013-08-09T13 :52 :33.166Z C 6 2013-08-09T13 :53 :33.166Z B 8 2013-08-09T13 :54 :33.166Z B 5

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

    my_parser.js

    var fs = require ("fs" ); function (err, logData ) { // Если произошла ошибка, то мы генерируем исключение, // и работа приложения завершается if (err) throw err; // logData имеет тип Buffer, переводим в string var text = logData.toString(); });

    Работать с файлами в Node.js очень просто благодаря встроенному модулю файловой системы fs . Этот модуль содержит функцию readFile , принимающую в качестве аргументов путь до файла и коллбэк. Коллбэк вызовется, когда завершится чтение файла. Данные из файла поступают в виде объекта типа Buffer , по сути представляющего собой массив байтов. Мы можем перевести его в строку с помощью функции toString ().

    Теперь давайте займёмся обработкой логов. Это вполне себе обычный код JavaScript, поэтому я не буду вдаваться в детали.

    my_parser.js

    var fs = require ("fs" ); // Считывание содержимого файла в память fs.readFile("example_log.txt" , function (err, logData ) { // Если произошла ошибка, то генерируем исключение, // и работа приложения завершится. if (err) throw err; // logData имеет тип Buffer, переводим в строку var text = logData.toString(); var results = {}; // Разбивка файла по строкам var lines = text.split("\n" ); lines.forEach(function (line ) { var parts = line.split(" " ); var letter = parts; var count = parseInt (parts); if (!results) { results = 0 ; } results += parseInt (count); }); console .log(results); // { A: 2, B: 14, C: 6 } });

    Теперь, когда вы передадите этот файл node в качестве аргумента, он выведет результат и завершит работу.

    $ node my_parser.js { A: 2 , B: 14 , C: 6 }

    Я часто использую Node.js для таких задач. Это простая и мощная альтернатива bash-скриптам.

    Асинхронные коллбэки

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

    Это особенно важно для веб-серверов. Доступ к базам данных в современных веб-приложениях - обычное дело. Пока вы ждёте ответа от базы, Node.js может обработать ещё запросы. Это позволяет вам обрабатывать тысячи одновременных соединений с очень маленькими затратами, сравнимыми с созданием отдельного потока для каждого соединения.

    Делаем что-нибудь полезное - HTTP-сервер

    Как я уже говорил ранее, Node.js не делает ничего «из коробки». Один из встроенных модулей позволяет без особых усилий создать простой HTTP-сервер , указанный в примере на сайте Node.js .

    my_web_server.js

    var http = require ("http" ); http.createServer(function (req, res ) { res.writeHead(200 , {"Content-Type" : "text/plain" }); res.end("Hello World\n" ); }).listen(8080 ); console .log("Server running on port 8080." );

    Когда я говорю, «простой», это значит «простой». Это не навороченный HTTP-сервер. Он не работает с HTML или изображениями. Фактически, что бы вы ни запросили, он вернёт Hello World . Тем не менее, можете запустить его, зайти на http://localhost:8080 в браузере и увидеть этот текст.

    $ node my_web_server.js

    Возможно, вы заметите небольшую разницу: ваше приложение не завершает работу. Так происходит потому, что вы создали сервер, и теперь он будет продолжать работать и отвечать на запросы до тех пор, пока вы не убьёте node сами.

    Если вы хотите превратить это приложение в полноценный веб-сервер, то вам придется потрудиться. Вам нужно будет проверять, что запрошено, читать соответствующие файлы и отсылать назад контент. Впрочем, есть и хорошая новость: другие уже сделали эту тяжкую работу за вас.

    Последнее обновление: 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"); });