Читать текстовый файл по строкам с помощью Node.js
Как получить доступ к строкам документа, когда можно читать только блоки данных?
Библиотека файловой системы Node предоставляет множество функций для чтения и записи файла. Можно загрузить весь файл в строку символа. Строки текста можно хранить в файле одну за другой. Но чего нельзя сделать, так это прочитать файл по строкам. Когда он очень большой или когда ты хочешь ограничить чтение рядом строк, этот пробел становится раздражающим.
Было предложено несколько решений этой проблемы, с дополнительным компонентом или без него, но ни одно из них не удовлетворительно, если ты хочешь воспроизвести функции PHP или C или любого другого языка: открыть файл, прочитать строку в цикле, закрыть файл.
Вот довольно простой алгоритм, который приводит к этому результату, который не требует внешнего модуля.
- Создается ассоциативный массив fileBuffer с ключевым ресурсом для файла, а по значению - массив, содержащий считанные строки. В
- таблице filePtr также есть ресурс файла, а в качестве значения - положение в файле.
- Проверяется, есть ли в таблице содержимое. Если да, то считывается первый элемент, который подавляется при помощи shift.
- В противном случае считывается блок данных в файле, начиная с позиции pos и размером 4096 байт.
- Фактическое количество прочитанных байтов возвращено в br.
- Если это число меньше 4096, другого чтения не будет, удаляем запись файла в filePtr (это будет использоваться функцией eof).
- Буфер преобразуется в строку и разделяется на массив, присвоенный fileBuffer [handle].
- Последний элемент таблицы стирается, поскольку в большинстве случаев строка усечена.
- Следующая позиция в файле определяется путем добавления числа прочитанных байтов за вычетом размера последнего элемента.
- Когда массив пуст, мы начинаем с 4, если только не обнаружен конец файла.
Исходный код модуля :
var fs = require('fs');
var filePtr = {}
var fileBuffer = {}
var buffer = new Buffer(4096)
exports.fopen = function(path, mode) {
var handle = fs.openSync(path, mode)
filePtr[handle] = 0
fileBuffer[handle]= []
return handle
}
exports.fclose = function(handle) {
fs.closeSync(handle)
if (handle in filePtr) {
delete filePtr[handle]
delete fileBuffer[handle]
}
return
}
exports.fgets = function(handle) {
if(fileBuffer[handle].length == 0)
{
var pos = filePtr[handle]
var br = fs.readSync(handle, buffer, 0, 4096, pos)
if(br < 4096) {
delete filePtr[handle]
if(br == 0) return false
}
var lst = buffer.slice(0, br).toString().split("\n")
var minus = 0
if(lst.length > 1) {
var x = lst.pop()
minus = x.length
}
fileBuffer[handle] = lst
filePtr[handle] = pos + br - minus
}
return fileBuffer[handle].shift()
}
exports.eof = function(handle) {
return (handle in filePtr) == false && (fileBuffer[handle].length == 0)
}
Модуль можно импортировать, как в приведенном ниже примере, или непосредственно интегрировать функции в его проект, удалив префикс exports.
Исходный код демонстрации
В этом примере файл считывается по строкам и записывается в новый файл по строкам, но с помощью функций File System.
var fs = require('fs')
var readline = require("/scripts/node-readline/node-readline.js")
var source="/scripts/node-readline/demosrc.html"
var target="/scripts/node-readline/demotgt.html"
var r=readline.fopen(source,"r")
if(r===false)
{
console.log("Error, can't open ", source)
process.exit(1)
}
var w = fs.openSync(target,"w")
var count=0
do
{
var line=readline.fgets(r)
console.log(line)
fs.writeSync(w, line + "\n", null, 'utf8')
count+=1
}
while (!readline.eof(r))
readline.fclose(r)
fs.closeSync(w)
console.log(count, " lines read.")
Замените имя исходного и целевого файлов тем, что нужно. Также можно адаптировать размер буфера под свои потребности. Если файл содержит строки длиннее 4096 байт (это довольно редко, когда его приходится читать по строкам), то буфер нужно увеличить пропорционально.
Загрузить полный исходный код.