Ошибка записи в файл fs потока NodeJS

Задача

Записать очень большой массив в файл, используя csv-write-stream и fs stream.

Фон

У меня есть небольшое приложение, которое записывает огромный массив данных (тысячи записей) в файл CSV. Чтобы добиться этого, я использую вышеупомянутую библиотеку, которая является ничем иным, как маской (удобством) для потока fs. Тем не менее, приложение вылетает во время выполнения, и я не знаю почему.

ошибка

Файл создается, и поток начинает запись в него, но затем во время выполнения у меня всегда одна и та же ошибка:

events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: write after end
    at writeAfterEnd (_stream_writable.js:166:12)
    at WriteStream.Writable.write (_stream_writable.js:211:5)
    at ondata (_stream_readable.js:536:20)
    at emitOne (events.js:77:13)
    at emit (events.js:169:7)
    at Readable.read (_stream_readable.js:368:10)
    at flow (_stream_readable.js:751:26)
    at WriteStream.<anonymous> (_stream_readable.js:609:7)
    at emitNone (events.js:67:13)
    at WriteStream.emit (events.js:166:7)

Код

Я знаю, что эта ошибка связана с этим фрагментом кода:

let writer = csvWriter({
    headers: ['country', 'postalCode']
});
let fsStream = fs.createWriteStream('output.csv');
writer.pipe(fsStream);

//very big array !
currCountryCodes = [{country: 'A', postalCode: 0}, {country: 'B', postalCode: 1 }];

for (let j = 0; j < currCountryCodes.length; j++) {
    writer.write(currCountryCodes[j]);
}

writer.end(function() {
  fsStream.end(function() {
    console.log('=== CSV written successfully, stopping application ===');
    process.exit();
  });
});

Наиболее конкретно к исполнению:

fsStream.end(function() {
        console.log('=== CSV written successfully, stopping application ===');
        process.exit();
      });

Но я не могу понять, почему это происходит. Так или иначе, это происходит только тогда, когда массив, который я пишу, имеет тысячи строк, а если у меня всего дюжина или около того, он работает отлично.

Вопрос

После прочтения ошибки у меня сложилось впечатление, что я все еще записываю в файл после закрытия потока, но этого не может быть, потому что эти функции запускаются, только когда все сброшено в файл (верно?)

  • Что не так в моем коде?

1 ответ

Решение

Проблема в том, что вы (по понятным причинам) предполагаете, что при обратном вызове для writer.end() вызывается, данные не будут записаны fsStream больше, что не так (как предполагает ошибка).

writer является дуплексным потоком, что означает, что он доступен как для чтения, так и для записи. Позвонив .end() метод, вы говорите, что больше не будете писать. Однако это не означает, что он все еще не будет читабельным.

Когда вы впоследствии закончите fsStream, в каком-то буфере все еще могут быть незагруженные данные, которые будут переданы fsStream, что дает ошибку.

Вы можете решить это, слушая end событие на writer, который является читаемым эквивалентом сигнализации о том, что больше нет данных для чтения:

writer.end(function() {
  writer.on('end', function() {
    fsStream.end(function() {
      console.log('=== CSV written successfully, stopping application ===');
      process.exit();
    });
  });
});

РЕДАКТИРОВАТЬ: Я думаю, что когда writer.end() вызывается, fsStream будет автоматически завершен (так fsStream.end() является излишним, и его обратный вызов не может быть вызван, потому что finish событие уже было выпущено).

Вы можете слушать finish событие на fsStream если вы хотите убедиться, что все данные были сброшены в выходной файл:

writer.end(function() {
  fsStream.on('finish', function() {
    console.log('=== CSV written successfully, stopping application ===');
    process.exit();
  });
});

Или даже:

fsStream.on('finish', function() {
  console.log('=== CSV written successfully, stopping application ===');
  process.exit();
});

writer.end();
Другие вопросы по тегам