Как записать массив JSON в файл с помощью Node.js writeStream?

Я написал небольшой скрипт Node.js для очистки данных с веб-сайта, на котором я перебираю страницы для извлечения структурированных данных.

Данные, которые я извлекаю для каждой страницы, представляют собой массив объектов.

Я подумал, что могу использовать метод fs.createWriteStream() для создания доступного для записи потока, в который я мог бы постепенно записывать данные после извлечения каждой страницы.

Судя по всему, в поток можно записать только String или Buffer, поэтому я делаю что-то вроде этого:

output.write(JSON.stringify(operations, null, 2));

Но, в конце концов, как только я закрываю поток, JSON имеет неверный формат, потому что очевидно, что я просто добавил каждый массив каждой страницы один за другим, в результате чего-то вроде этого:

[
    { ... },  /* data for page 1 */
    { ... }
][ /* => here is the problem */
    { ... },  /* data for page 2 */
    { ... }
]

Как я могу приступить к добавлению массивов в вывод, а не связывать их в цепочку? Это вообще выполнимо?


person ClementParis016    schedule 25.01.2018    source источник
comment
Есть ли причина, по которой вы не пишете все за один раз, после обработки всех страниц? Все остальное кажется немного хакерским.   -  person user1751825    schedule 25.01.2018
comment
Это потому, что весь массив в конце концов довольно большой, поэтому хранение его в памяти может в конечном итоге повлиять на производительность, я думаю (не уверен, это просто любимый проект для меня, чтобы узнать, как работают потоки)   -  person ClementParis016    schedule 25.01.2018
comment
Проблема в том, что нет возможности получить частичные (действительные) данные json. На самом деле это не то, что можно транслировать каким-либо осмысленным образом. Если массив настолько велик, что может повлиять на производительность, то окончательный результирующий файл json будет слишком большим для эффективного использования в любом случае.   -  person user1751825    schedule 25.01.2018
comment
Если вам действительно нужно выводить прогрессивно, то просто выводите каждый объект операции отдельно и расставляйте квадратные скобки и запятые по мере необходимости.   -  person user1751825    schedule 25.01.2018
comment
Хорошо, пока у меня есть несколько возможностей попробовать: 1) полностью записать файл в конце процесса, 2) создать JSON вручную как строку при записи в поток (как вы предложили) и 3) как последнее последнее средство, напишите один файл на страницу. Спасибо за вашу помощь, я покопаюсь в этих решениях и выясню, какое из них работает лучше всего;)   -  person ClementParis016    schedule 25.01.2018


Ответы (1)


Ваши варианты будут...

  1. Держите полный массив в памяти и записывайте в файл json только в конце, после обработки всех страниц.
  2. Напишите каждый объект отдельно, а квадратные скобки и запятые обработайте вручную.

Что-то вроде этого...

//start processing
output.write('[');
//loop through your pages, however you're doing that
while (more_data_to_read()) {
    //create "operation" object
    var operation = get_operation_object();
    output.write(JSON.stringify(operation, null, 2));
    if (!is_last_page()) {
        //write out comma to separate operation objects within array
        output.write(',');
    }
}
//all done, close the json array
output.write(']');

Это создаст правильно сформированный json.

Лично я бы выбрал № 1, так как это кажется более «правильным» способом сделать это. Если вас беспокоит, что массив использует слишком много памяти, то json может быть не лучшим выбором для файла данных. Он не особенно хорошо подходит для чрезвычайно больших наборов данных.

В приведенном выше примере кода, если процесс был прерван на полпути, у вас будет недопустимый файл json, поэтому постепенная запись на самом деле не сделает приложение более отказоустойчивым.

person user1751825    schedule 30.01.2018
comment
Спасибо, я закончил запись файла в конце обработки (вариант 1), что действительно является самым безопасным. На данный момент он работает хорошо, поэтому урок здесь не пытается слишком рано оптимизировать :) - person ClementParis016; 30.01.2018
comment
1-й подход не работает, если размер массива огромен. В моем случае это было более 1,5 миллионов объектов. JSON.stringify выдавал ошибку головы JAVASCRIPT из памяти. - person Irfan Raza; 06.03.2020