Skip to content

Чтение и запись файлов в Node.js

19/03/2010

Операции с файлами языку 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[0]);
fs.closeSync(file_handle);
9 комментариев
  1. Александр Дорофеев permalink

    Поимел недавно очень серьезную проблему именно с этой подсистемой. Подробнее об этом по этому адресу http://github.com/ry/node/issues#issue/112.

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

    • Ценное замечание, спасибо ) Я пока не сталкивался, может быть потому что всегда читаю/пишу файл целиком (в основном в целях дебага).

      • Александр Дорофеев permalink

        Вы не можете попытаться воспроизвести этот баг? Судя по комментариям Райана — ему не удалось, и он на него элементарно забил. Вот мне и интересно — сломан ли у меня мозг?

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

  2. Roman permalink

    Здравствуйте, подскажите пожалуйста как можно организовать следущую функцию.
    Пример:
    Мне нужно из mp3 вырезать припев, с 30 секунды по 45 получить новый файл, как узнать с какого килобайта начинаться 30 секунда по 45.

  3. Сергей permalink

    Полезная статья мне лично пригодилась.Спасибо.

Trackbacks & Pingbacks

  1. Чтение и запись файлов в Node.js « nodeJS

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: