Блог о веб-технологиях и JavaScript

Чтение и запись файлов в NodeJS

В этой статье я расскажу как читать и записывать файлы используя синхронные и асинхронные варианты функций NodeJS, а также потоки.

Запись файлов

Самый простой на мой взгляд метод записи в файл:

var fs = require('fs');
fs.writeFileSync('/some/path/test.txt', 'Привет');

Это вариант синхронной записи. В этом случае происходит запись в файл, а затем программа продолжает выполнение. Вариант асинхронной записи:

var fs = require('fs');
fs.writeFile("/some/path/test.txt", "Привет!", function(err) {
    if(err) {
        console.log(err);
    } else {
        console.log("Файл сохранен.");
    }
});

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

Чтение файлов

Синхронное чтение:

var fs = require('fs');
var text = fs.readFileSync('/some/path/test.txt', 'utf8');

Второй параметр это кодировка. Без указания этого параметра функция readFileSync возвращает объект buffer.

Асинхронное чтение:

fs.readFile('/some/path/test.txt', {encoding: 'utf8'}, function (err, data) {
    if (err) throw err;
    console.log(data);
});

Здесь также нужно передать опцию encoding иначе функция вернет буфер данных.

Использование потоков

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

var fs = require('fs');
var stream = fs.createReadStream('/some/path/test.txt', {encoding: 'utf8'});
stream.on('readable', function() {
    var buf;
    while ((buf = stream.read()) !== null) {
        console.log(buf);
    }
});

stream.once('end', function() {
    console.log('Чтение выполнено успешно.');
});

Здесь мы указываем название файла и кодировку, и как только в потоке появятся доступные для чтения данные, выполнится событие readable, обработчик которого выполняет чтение. Функция read объекта stream выполнит чтение всех доступных данных, либо то их количество, которое указано первым параметром, например stream.read(1024).

Теперь выполним запись в файл используя поток Writable:

var fs = require('fs');
var writer = fs.createWriteStream('test.txt', {flags: 'w'});
writer.on('finish', function() {
    console.error('Запись выполнена успешно.');
});
var i = 0;
function write() {

    do {
        var ok = writer.write('Тест, #' + i + '!\n');

        if (!ok) {
            writer.once('drain', write);
            break;
        }

        i++;

    } while (i < 10 && ok);

    if (i === 10) {
        writer.end('===== Конец =====\n');
    }
}
write();

В этом примере выполняется запись десяти строк в файл. Собственно запись выполняется вызовом функции writer.write(text). Если эта функция возвращает значение true, то значит запись успешно выполнена, если же false, то это значит что данные еще не записаны и ожидают своей очереди в буфере, в этом случае нужно подождать событие drain:

writer.once('drain', write);

Когда данные из буфера записаны, вызывается событие drain и мы можем продолжить запись остальных данных.

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

var fs = require('fs');
var source = fs.createReadStream('file1.txt');
var target = fs.createWriteStream('file2.txt');
source.pipe(target);

В этом примере мы копируем файл file1.txt в файл file2.txt, причем запись происходит по мере того, как поток чтения считывает данные в буфер. Если нам еще нужно преобразовывать содержимое файла, то можно добавить еще и поток преобразования — Transform:

var fs = require('fs');
var Transform = require('stream').Transform;

var uppercase = new Transform({decodeStrings: false});
uppercase._transform = function(chunk, encoding, done) {
  done(null, chunk.toUpperCase());
};

var source = fs.createReadStream('file1.txt', {encoding: 'utf8'});
var target = fs.createWriteStream('file2.txt');
source.pipe(uppercase).pipe(target);

После выполнения этого кода, в файле file2.txt будет точно такое содержимое, как и в файле file1.txt, но только прописью.

Если вы хотите узнать больше о работе с файлами в NodeJS, рекомендую видео уроки Ильи Кантора Node.JS от А до Я.

Node Version Manager — управление версиями NodeJS

NVM (Node Version Manager) — это bash скрипт, который позволяет управлять версиями NodeJS. Например, у меня локально установлены стабильная, а также бета версия, на которую я переключаюсь когда необходимо потестировать новые функции (генераторы, Maps, Sets и прочее).

Установка

Установка производится при помощи инсталляционного скрипта или вручную. Я пробовал второй вариант, поэтому опишу только его. Для этого вам понадобится GIT:

git clone git://github.com/creationix/nvm.git ~/.nvm

Чтобы скрипт nvm стал доступен в консоли, нужно добавить вызов команды source при запуске консоли. Я использую bash, поэтому в файл ~/.bashrc добавил следующее:

export NVM_HOME="$HOME/.nvm"
if [ -f "$NVM_HOME/nvm.sh" ]; then
    source "$NVM_HOME/nvm.sh"
fi

Дополнительно я добавил туда же и bash_completion чтобы включить автодополнение в nvm:

if [ -f "$NVM_HOME/bash_completion" ]; then
    source "$NVM_HOME/bash_completion"
fi

Использование

Теперь установим 2 версии NodeJS — стабильную и нестабильную. В NodeJS все чётные версии являются стабильными, а нечетные — нестабильными. Смотрим список доступных версий:

nvm ls-remote

Из полученного списка выбираем две и устанавливаем их:

nvm install v0.10.12
nvm install v0.11.2

Если все прошло успешно, то команда nvm ls покажет нам установленные версии. Переключаемся между версиями используя команду use:

nvm use v0.11.2

Набирать версии не очень удобно, поэтому можно назначить псевдоним (alias) какой-либо версии:

nvm alias stable v0.10.12
nvm alias beta v0.11.2

Теперь, чтобы переключиться на стабильную версию NodeJS выполняем команду:

nvm use stable

Если мы укажем alias с названием default (то есть «по умолчанию»), то каждый раз, когда мы будем запускать консоль, nvm будет переключаться на эту версию.

nvm alias default v0.10.12

Удаление псевдонима выполняется командой nvm unalias, а удаление версий NodeJS — nvm uninstall.

Больше информации о nvm:

Альтернативные менеджеры:

  • n Менеджер версий от TJ Holowaychuk
  • nodist Менеджер версий для Windows
  • nodever

Хостинг NodeJS сайтов через Varnish

Если необходимо запускать на сервере сразу несколько веб приложений, то это можно делать при помощи прокси сервера Varnish. Таким образом можно хостить множество приложений NodeJS, а также Apache, Tomcat и прочее. Схема работы проста — Varnish устанавливается на порт 80, приложения NodeJS (Apache, Nginx) на другие свободные порты. Когда поступает запрос на порт 80, Varnish по имени хоста определяет какому именно приложению оно предназначается и передает запрос туда.

Теперь подробнее и по порядку (перечисленные ниже инструкции я опробовал на своем Ubuntu сервере, для других дистрибутивов или OS процедура может отличаться).

Устанавливаем Varnish

Выполняем команду:

sudo apt-get install varnish

После того, как Varnish установится, редактируем файл /etc/default/varnish, указываем порт 80 в DAEMON_OPTIONS (после параметра -a):

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

Настраиваем прокси на web приложения

Откройте VCL файл /etc/varnish/default.vcl и добавьте туда конфигурацию backend:

backend apache {
    .host = "127.0.0.1";
    .port = "8001";
}

backend example_nodejs {
    .host = "127.0.0.1";
    .port = "3000";
}

backend jenkins {
    .host = "127.0.0.1";
    .port = "8080";
}

Здесь я указал 3 backend-а и назначил им понятные мне названия. Далее указываем маршруты при помощи параметра sub vcl_recv:

sub vcl_recv {
    if(req.http.host == "example.com" || req.http.host == "www.example.com") {
        set req.backend = apache;
    }
    if(req.http.host == "nodejs.example.com" || req.http.host == "www.nodejs.example.com") {
        set req.backend = example_nodejs;
    }
    if(req.http.host == "ci.example.com" || req.http.host == "www.ci.example.com") {
        set req.backend = jenkins;
    }
}

Маршруты указывают куда необходимо отправлять запросы в зависимости от имени хоста. В моем примере, хост nodejs.example.com будет передаваться в backend example_nodejs, т.е. приложение, работающее на 127.0.0.1:3000.

Далее перезапускаем Varnish:

sudo service varnish restart

После этого все должно работать.

Если вам нужно запустить множество приложений NodeJS, можно использовать forever, либо через Upstart скрипт (актуально для Ubuntu). Инструкцию для запуска NodeJS приложений через Upstart можно найти здесь (англ.).

Источник — How to run Apache and NodeJS based sites on the same server with Varnish.

Lightgallery 1.4 Beta

Сегодня я обновил лайтбокс скрипт Lightgallery. Исправил некоторые ошибки, самая серьезная среди которых — пропадание оверлея в IE9. Шестая версия Internet Explorer больше не поддерживается. Также улучшена анимация с использованием requestAnimationFrame. Удалены опции speed и framesNumber, вместо них используется простая и понятная опция duration — если установить её в 1000, то анимация будет длиться одну секунду. Размер скрипта в сжатом виде уменьшился — теперь всего 8,5K.
Демо можно посмотреть здесь. Буду признателен за тестирование, замечания.

LightGallery 1.3

После некоторого перерыва, я выпустил новую версию LightGallery — скрипта-галереи в стиле lightbox. Основное отличие от других подобных скриптов состоит в том, что LightGallery не требует сторонних скриптов. Просто подключаете на веб-страницу, и все готово к работе.

Читать дальше >>

Страница 1 из 2312345678910»...Последняя »
Дмитрий Ищенко © 2007 - 2014