Як закрити читабельний потік (до кінця)?


90

Як закрити читабельний потік у Node.js?

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   // after closing the stream, this will not
   // be called again

   if (gotFirstLine) {
      // close this stream and continue the
      // instructions from this if
      console.log("Closed.");
   }
});

Це було б краще, ніж:

input.on('data', function(data) {
   if (isEnded) { return; }

   if (gotFirstLine) {
      isEnded = true;
      console.log("Closed.");
   }
});

Але це не зупинило б процес читання ...


6
Попередження: Це питання лише в контексті fsмодуля. closeне існує в Stream.Readable.
zamnuts

3
Хороші новини. Версія 8 вузла надаєstream.destroy()
joeytwiddle

ти не можеш зателефонуватиreadable.push(null) && readable.destroy();
Олександр Міллз

Відповіді:


39

Закликати input.close(). Це не в документах, але

https://github.com/joyent/node/blob/cfcb1de130867197cbc9c6012b7e84e08e53d032/lib/fs.js#L1597-L1620

чітко виконує роботу :) Це насправді робить щось подібне до вашого isEnded.

EDIT 2015-квітня-19 На основі коментарів нижче, а також для уточнення та оновлення:

  • Ця пропозиція є хакерською і не задокументована.
  • Хоча, дивлячись на струм, lib/fs.jsвін все одно працює> 1,5 року пізніше.
  • Я погоджуюсь із коментарем нижче про те, що дзвінки destroy()є кращими.
  • Як правильно зазначено нижче, це працює для Росії fs ReadStreams, а не для загальногоReadable

Що стосується загального рішення: воно не виглядає так, ніби воно є, принаймні з мого розуміння документації та швидкого перегляду _stream_readable.js.

Моя пропозиція буде перевести ваш читабельний потік у призупинений режим, принаймні, запобігаючи подальшій обробці у вихідному джерелі даних. Не забудьте unpipe()та видаліть усі dataпрослуховувачі подій, щоб pause()насправді було зроблено паузу, як зазначено у документах


Зробіть це довше: додайте кілька посилань із документації! :-)
Ionică Bizău

2
Дуже добре! Здається, вихідний код є найкращим ресурсом документації. ;-)
Ionică Bizău

Насправді я волів би зателефонувати destroy. Принаймні так називається, якщо встановити autoClose на true. Дивлячись на вихідний код (сьогодні), відмінності мінімальні ( destroyдзвінки close), але це може змінитися в майбутньому
Марсело Дініз

@NitzanShaked Файл оновлено. Це правильне посилання: github.com/joyent/node/blob/… ? (він містить ідентифікатор
коміту

4
Немає close()на об'єкті читабельності, чи існує рішення ніколи? Мій обмін даними завжди неповний ...
CodeManX

74

Редагувати: Хороші новини! Починаючи з Node.js 8.0.0 readable.destroyофіційно доступний: https://nodejs.org/api/stream.html#stream_readable_destroy_error

ReadStream.destroy

Ви можете викликати функцію ReadStream.destroy у будь-який час.

var fs = require('fs');

var readStream = fs.createReadStream('lines.txt');
readStream
    .on('data', function (chunk) {
        console.log(chunk);
        readStream.destroy();
    })
    .on('end', function () {
        // This may not been called since we are destroying the stream
        // the first time 'data' event is received
        console.log('All the data in the file has been read');
    })
    .on('close', function (err) {
        console.log('Stream has been destroyed and file has been closed');
    });

ReadStream.destroyВідкрита функція не задокументована (Node.js v0.12.2), але ви можете поглянути на вихідний код на GitHub ( комісія 5 жовтня 2012 р.).

destroyФункція внутрішньо відзначте ReadStreamекземпляр знищеними і викликає closeфункцію , щоб звільнити файл.

Ви можете прослухати подію закриття, щоб точно знати, коли файл закритий. Подія закінчення не спрацьовуватиме , якщо дані не будуть повністю витрачені.


Зверніть увагу, що destroyclose) функції специфічні для fs.ReadStream . Немає частини загального потоку. Читабельний "інтерфейс".


Принаймні в останній версії Node (не перевіряв інші), дескриптор файлу закривається автоматично . Тим не менш, я не робив жодного ретельного тесту, щоб переконатися, що потік врешті-решт спрацює, errorякщо його ніколи не прочитати. Окрім цього, єдиним іншим витоком, про який я б турбувався, є обробники подій - ще раз, я не впевнений у цьому на 100%, але ми можемо бути в порядку b / c 2010 Євангеліє Ісаака каже, що обробники є обрізаний, коли випромінювачі gc'd: groups.google.com/d/msg/nodejs/pXbJVo0NtaY/BxUmF_jp9LkJ
mikermcneil

1
Якщо даних замало, функція on('data') спрацьовує лише один раз, тому їх не буде .close(), просто нагадайте комусь іншому.
bitfishxyz


12

Ви не можете. Станом на Node 5.3.0 не існує жодного задокументованого способу закрити / вимкнути / перервати / знищити загальний читабельний потік. Це обмеження архітектури потоку Node.

Як пояснили інші відповіді, існують недокументовані хаки для конкретних реалізацій Readable, що надаються Node, таких як fs.ReadStream . Однак це не загальні рішення для будь-якого читабельного.

Якщо хтось може довести, що я тут не правий, будь ласка. Я хотів би мати можливість робити те, що, як я кажу, неможливо, і був би радий виправлення.

EDIT : Ось моє обхідне рішення: впровадити .destroy()для мого конвеєру складну серію unpipe()дзвінків. І попри всю цю складність, вона не працює належним чином у всіх випадках .

EDIT : Вузол v8.0.0 додав destroy()API для читабельних потоків .


1
Зараз існує заява stream.pipeline, що обробляє "помилки переадресації та належне очищення та забезпечує зворотний виклик, коли трубопровід завершено". Це допомагає?
andrewdotn

11

У версії 4.*.*натискання нульового значення в потік викликає EOFсигнал.

З документації nodejs

Якщо передано значення, відмінне від null, метод push () додає шматок даних у чергу для подальшого використання потокових процесорів. Якщо значення null передано, це сигналізує про кінець потоку (EOF), після чого більше не можна писати дані.

Це спрацювало для мене, спробувавши численні інші варіанти на цій сторінці.


1
Працює для мене. Однак мені потрібно було уникати виклику зворотного виклику done () після натискання null, щоб отримати очікувану поведінку - а саме, що весь потік зупиняється.
Rich Apodaca

6

Цей модуль знищення призначений для забезпечення знищення потоку, обробки різних API та помилок Node.js. Зараз це один з найкращих виборів.

Примітка. З Node 10 ви можете використовувати .destroyметод без подальших залежностей.


3

Ви можете очистити та закрити потік yourstream.resume(), який скине все на потік і врешті-решт закриє його.

З офіційних документів :

readable.resume ():

Повернення: це

Цей метод призведе до того, що читабельний потік відновить випуск подій "даних".

Цей метод переведе потік в режим течії. Якщо ви не хочете споживати дані з потоку, але хочете дістатися до його події 'end', ви можете зателефонувати stream.resume (), щоб відкрити потік даних.

var readable = getReadableStreamSomehow();
readable.resume();
readable.on('end', () => {
  console.log('got to the end, but did not read anything');
});

Це можна назвати «зливанням» потоку. У нашому випадку, звичайно, у нас був 'data'прослуховувач подій, але ми зробили так, щоб він перевіряв логічну форму, if (!ignoring) { ... }щоб він не обробляв дані під час зливу потоку. ignoring = true; readable.resume();
joeytwiddle

5
Звичайно, це передбачає потік 'end'у певний момент. Не всі потоки це зроблять! (Наприклад, потік, що надсилає дату щосекунди, назавжди.)
joeytwiddle

3

Це старе запитання, але я теж шукав відповіді і знайшов найкращий для мого впровадження. І ті, endі інші closeподії випускаються, тому я думаю, що це найчистіше рішення.

Це зробить фокус у вузлі 4.4. * (Стабільна версія на момент написання):

var input = fs.createReadStream('lines.txt');

input.on('data', function(data) {
   if (gotFirstLine) {
      this.end(); // Simple isn't it?
      console.log("Closed.");
   }
});

Для дуже детального пояснення див .: http://www.bennadel.com/blog/2692-you-have-to-explicitly-end-streams-after-pipes-break-in-node-js.htm


2

Цей код тут добре виконає фокус:

function closeReadStream(stream) {
    if (!stream) return;
    if (stream.close) stream.close();
    else if (stream.destroy) stream.destroy();
}

writeStream.end () - це спосіб закрити writeStream ...


1
Чому ви згадуєте .end () - це шлях, але тоді ваш код використовує закриття та знищення і навіть не використовує end?
Лукас Б

1
я закриваю readStream у прикладі ... a writeStream - use.end
g00dnatur3
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.