Чтение первых строк из текстового файла без загрузки всего текстового файла в память - PullRequest
0 голосов
/ 29 февраля 2020

У меня есть большое количество небольших текстовых файлов, где первые 4 или менее строки содержат метаданные; Ниже приведен пример

Lorem Ipsum

Tag1 Tag2 Tag3

Текст

4204

Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit, Sed Do EiusMod Tempor Incididunt U Labore et Dolore Magna Aliqua. Ut enim ad minim veniam, упражнение в полном объеме Duis aute irure dolor в репеэндерит в волпуте Velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat непроизведенный, иск в виновном виновнике dellrunt mollit anim id labour.

  • Lorem Ipsum; будет заголовок
  • Tag1, Tag2 и Tag3; будет массив тегов
  • Text; будет тип
  • 4204; будет идентификатором.
  • Lorem ipsum [...]; будет фактическим содержанием

Мне нужно загрузить метаданные без загрузки фактического содержимого. Я работаю в node.js. Я сделал следующий код:

function readMeta (path, callback) {
    const meta = {};
    const lineReader = require("readline").createInterface({input: require("fs").createReadStream(path)});

    let lineCount = 0;
    let interpretedMeta;

    lineReader.on("line", line => {

        interpretedMeta = interpretMeta(line, lineCount) 

        switch (lineCount) {
            case 0:
                meta.name = interpretedMeta;
                break;
            case 1:
                meta.tags = interpretedMeta.split(" ");
                break;
            case 2:
                meta.type = interpretedMeta;
                break;
            case 3:
                meta.id = interpretedMeta;
        }

        ++lineCount;


        if (/^\s*$/.test(line)) {
            lineReader.close();
        }
    });
    lineReader.on("close", () => {
    callback(meta);
    process.exit(0);
    });
}

, где interpretMeta() - это функция, которая форматирует строку, заданную на основе номера белья. Я включу это в readMeta() позже, так как он несколько избыточен.

Проблема

Этот код работает с одним файлом, но выдает ошибки, если он запускается несколько раз за короткое время. Он достигает второй строки, но затем запускается при каждом запуске функции.

Я не уверен на 100%, почему это происходит, но я предполагаю, что что-то вроде обратного вызова lineReader.on() не делает копии переменных получает от readMeta случается. Я не могу понять, как отлаживать или решать.

Исправление

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

A: исправить код

B: сделать синхронную функцию 'readline`

Спасибо

1 Ответ

0 голосов
/ 01 марта 2020

Пользователь О. Джонс прокомментировал исходное сообщение с вопросом, ответит ли этот ответ на мой вопрос. Утвержденный ответ не был получен, но ответ ниже от Ведущий разработчик поставил меня на правильный путь:

Обновление в 2019

Замечательный пример уже опубликован в официальной Nodejs документации. здесь

Для этого требуется, чтобы на вашем компьютере была установлена ​​последняя версия Nodejs. > 11.4

const fs = require('fs');
const readline = require('readline');

async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');

const rl = readline.createInterface({
   input: fileStream,
   crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.

for await (const line of rl) {
   // Each line in input.txt will be successively available here as `line`.
   console.log(`Line from file: ${line}`);
}
}

processLineByLine();

Страница , на которую он ссылается , содержит еще один пример, которому я в итоге следую, мой окончательный код ниже:

async function readMeta (path) {
    const meta = {};
    const lineReader = require("readline").createInterface({input: fs.createReadStream(path)});

    let currentLine = 0;

    lineReader.on("line", line => {


        switch (currentLine) {
            case 0:
                meta.name = line;
                break;
            case 1:
                meta.tags = line.split(" ");
                break;
            case 2:
                meta.type = line;
                break;
            case 3:
                meta.id = +line;
        }

        ++currentLine;


        if (/^\s*$/.test(line)) {
            lineReader.close();
        }
    });
    await once(lineReader, "close");

    return meta;
}

Спасибо за помощь.

...