Readline останавливается после 55 строк. Как читать входные данные из стандартного ввода в узле JS? - PullRequest
4 голосов
/ 15 марта 2019

У меня есть "простая" проблема, которую я не могу обойти.Я просто собираюсь прочитать ввод со стандартного ввода (терминала), а затем сохранить ввод в переменную (здесь массив), а затем распечатать все это на терминале.Когда я пытаюсь вставить более 55 строк текста, программа просто распечатывает первые 55 строк (моего ввода) и затем завершает работу.Я не могу понять, почему это останавливается и как это исправить.

Мой код:

let readline = require('readline');
let rl = readline.createInterface({
    input: process.stdin,
    terminal: true
})

let inputLines = []

const pushLinesToArray = function (line) {
    inputLines.push(line)
  }

const readOneLine = function () {
    return new Promise((resolve, reject) => {
        rl.on('line', resolve)  
        }).then(rl.on('line', pushLinesToArray))
}

const start = async () => {

    // Save all input to inputLines array
    await readOneLine()

    // Print inputLines array to terminal/console
    inputLines.forEach((line) => console.log(line))
    process.exit()
}

start()

Как обойти эту проблему?Я должен также упомянуть, что когда я меняю функцию (readOneLine) выше на код внизу, она работает, ЕСЛИ я закрываю программу с помощью ctrl + C (Mac OSX).Это заставляет меня думать, что нет ничего общего с maxLineLength или буфером памяти.Единственное, что я изменил ниже, это close вместо line первое rl.on

const readOneLine = function () {
    return new Promise((resolve, reject) => {
        rl.on('close', resolve)  
        }).then(rl.on('line', pushLinesToArray))
}

Я должен также упомянуть, что собираюсь немного обработать ввод перед тем, как его распечататьиз.В приведенном выше коде я просто забрал все это, потому что я понимаю, что уже была проблема с чтением ввода. т.е. я хочу прочитать ввод более 55 строк текста.Затем сохраните текст в массив (строка за строкой).Затем выполните мой другой код (чтобы вычислить, сколько у каждого человека в долгу).И, наконец, распечатайте его.

Пример ввода будет выглядеть следующим образом: Note that there is new line after line 12

Когда я копирую -> вставьте это как ввод (и отметьтекаждая строка (1-13)) эта работа.Если у меня, с другой стороны, 57 строк, подобных этой (где строка № 1-56 с текстом, а строка № 57 пуста), это не сработает.Затем моя программа завершает работу после печати первых 55 строк с текстом (строка № 56 никогда не будет напечатана)

Редактировать: мне нужно это для работы с Kattis (онлайн-сайт для проблем программирования) иединственное, что я знаю, это то, что они запускают мой код с вышеупомянутыми флагами: -c {files}.Мне нужно изменить мой код, чтобы он мог обрабатывать различные вводные данные всего от 3 строк до 100 000 строк.Ввод всегда будет происходить в виде фрагмента (строка со всеми копиями строк -> вставленная в терминал), и мне нужно подключить слушатель или прочитать этот ввод и что-то с ним сделать (вычислить все), прежде чем я распечатываю ответ натерминал.Поэтому я все еще ищу ответ, чтобы решить эту проблему ввода.

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Использование обещания в этом случае необходимо изменить.Поскольку обещание разрешает в прочитанной первой строке, await в start() разблокируется и готовится обработать, сколько строк было прочитано к тому времени.Вероятно, ввод сокращается, потому что вы не дали достаточно времени для чтения всего ввода.

Либо удалите обещание и обработайте строки по мере их поступления:

rl.on('line', (line) => console.log(line));

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

const readOneLine = function () {
    return new Promise((resolve, reject) => {
        rl.on('line', pushLinesToArray)
        rl.on('close', () => resolve(inputLines))  
    })
}

Как указано в документе node.js для стандартного модуля readline [1], событие close выполняется, когдавсе доступные входные данные считываются или закрываются клиентом.

Поскольку вы также хотите обрабатывать пустую строку в качестве метки закрытия для потока, это можно сделать в line event.

const readOneLine = function () {
    return new Promise((resolve, reject) => {
        rl.on('line', (line) => {
            if (line === '') {
                resolve(inputLines);
                rl.close();
                return;
            }
            pushLinesToArray(line)
        })
        rl.on('close', () => resolve(inputLines))  
    })
}

Первый resolve(), который получает шанс на запуск, разблокирует await.Ничего вредного не произойдет, если resolve() запускается дважды, после пустой строки и Ctrl + C.

[1] https://nodejs.org/api/readline.html#readline_event_close

1 голос
/ 15 марта 2019

Я думаю, что проблема, с которой вы сталкиваетесь, заключается в том, что readline поставляется с размером буфера по умолчанию 4 КБ, который не будет считываться. Вам нужно будет установить maxLineLength в его настройках.

См. это .

...