2015-10-08 2 views
2

Я хочу загрузить (поток) управление процессом записи. Но процесс записи всегда возвращает false. Прекращается процесс загрузки больших файлов. Результат кода выглядит следующим образом:Node.js writable.write return false?

> Node app.js 
> False 
> False 
> False 
> False 

Что я делаю неправильно?

Мой код;

app.js

var http = require('http'); 
var fs = require('fs'); 

http.createServer(function(req, res){ 
    var readable = fs.createReadStream('read.mkv'); 
    var writable = fs.createWriteStream('write.mkv'); 

    readable.on('data', function(chunk){ 

     var buffer = writable.write(chunk); 

     if(!buffer){ // ----> Always false! Why???? 

     readable.pause(); 
     } 
     console.log(buffer); 
    }); 

    writable.on('drain', function(){ 

    readable.resume(); 
    }); 
}).listen(8090); 
+0

Пожалуйста, ответьте мне. –

+0

как вы знаете, что writable.write всегда возвращает true? какое сообщение об ошибке/код вы получаете в больших файлах? Кроме того, можете ли вы попробовать readable.pipe (writeable), чтобы увидеть, воспроизводится ли одна и та же ошибка? – prasun

+0

См. Здесь http://stackoverflow.com/questions/18932488/how-can-i-use-the-drain-event-with-createwritestream-method-in-node-js – Nick

ответ

0

Я изменил свою программу, чтобы показать больше информации о том, что происходит:

'use strict'; 
const fs = require('fs'); 

const readable = fs.createReadStream('read.mkv'); 
const writable = fs.createWriteStream('write.mkv'); 

readable.on('data', function(chunk){ 
    var buffer = writable.write(chunk); 

    if(!buffer){ // ----> Always false! Why???? 
    readable.pause(); 
    } 
    console.log(buffer, chunk.length); 
}); 

writable.on('drain', function(){ 
    readable.resume(); 
    console.log('drain'); 
}); 

Выход:

$ node blah.js 
false 65536 
drain 
false 65536 
drain 
false 65536 
drain 
true 8192 

Я также использовал другой размер файл в качестве ввода, так что у меня есть один true в конце моего вывода. Если бы я увеличил свой размер read.mkv, например, 10000 байт, последняя строка будет читать false 18192.

Что происходит, что каждый кусок возвращаемого read() достаточно велико, что вызывает поток записи превысит его highWaterMark, который по умолчанию 16384 (при условии, что поток, возвращаемый fs.createWriteStream). Как видно из цифр на выходе, каждый read() (err, каждый случай 'data') производит 65536 байт, за исключением последнего. Поскольку запись этого количества данных в writable приводит к тому, что он превышает его highWaterMark, этот поток советует дождаться 'drain' перед продолжением.

Итак, вы всегда видите false, потому что поток readable создает такие большие куски при чтении. И я ожидал бы, что больше не видно никаких журналов, что передача завершена. Но вам действительно нужно зарегистрировать .on('end') и .on('error'), чтобы понять это.

Для простого случая, как это, на самом деле лучше всего использовать readable.pipe(), как:

readable.pipe(writable); 

Это будет автоматически обрабатывать 'drain' для вас. Он даже вызовет writable.end() для вас соответствующим образом.

Обратите внимание, что pipe() не будет звонить writable.end(), если встречает ошибку чтения или записи. Если у вас есть длительный процесс, который должен быть устойчивым к ошибкам потока, вам необходимо убедиться в том, что они обрабатывают ошибки и закрывают потоки, чтобы предотвратить утечку дескриптора, если ваша программа работает достаточно долго, чтобы достигнуть предела дескриптора файла.

Что false Средства

Потоки позволяют программы для масштабирования больших объемов данных путем обработки его кусок в то время, а не загружаются все это в памяти. Потоки могут быть организованы в конвейеры, представляющие различные преобразования данных, прежде чем они будут окончательно выписаны. Когда write() возвращает false, это сигнализирует о том, что он получил достаточно данных, чтобы поддерживать его в течение некоторого времени. Если вы продолжаете отправлять ему куски, он будет продолжать принимать эти куски.Тем не менее, его отставание данных будет расти и начнет потреблять больше памяти. Если вы проигнорируете это возвращаемое значение и продолжаете отправлять данные из очень большого источника, вы даже можете заставить программу исчерпать адресное пространство и сбой или застревать. Чтобы ваш код был масштабируемым, вы должны уважать ответ false и ждать 'drain ', как это было в вашем коде.

Однако false не означает, что произошло что-то плохое или что-либо возникли ошибки. Фактически, в любом сценарии, когда поток источника быстрее, чем целевой поток, ожидается, что это произойдет, и способ API потоков сохраняет все в безопасности.