2016-04-02 2 views
3

В соответствии с nodeJS docs(v5.10.0) для Readable потока:Набор кодирования для преобразования потока nodeJS безопасным способом

лучше использовать readable.setEncoding('utf8'), чем работа с буферов непосредственно с помощью buf.toString(encoding). Это происходит потому, что «символы многобайтовыми (...) в противном случае потенциально наломать бы. Если вы хотите прочитать данные в виде строк, всегда использовать этот метод.

Мой вопрос о том, как это реализовать с помощью нового API для преобразования потоков. Там нет необходимости в настоящее время, чтобы пройти через многословной метод наследования.

так, к примеру, это будет работать как способ преобразования стандартного ввода в верхний регистр строки

const transform = require("stream").Transform({ 
    transform: function(chunk, encoding, next) { 
    this.push(chunk.toString().toUpperCase()); 
    next(); 
    } 
}); 

process.stdin.pipe(transform).pipe(process.stdout); 

Однако это выглядело бы как t o идти против рекомендации не использовать toString() на буферах. Я попытался модифицировать Трансформирование экземпляра, установив кодировку «UTF-8», как это:

const transform = require("stream").Transform({ 
    transform: function(chunk, encoding, next) { 
    this.push(chunk.toUpperCase()); //chunk is a buffer so this doesn't work 
    next(); 
    } 
}); 
transform.setEncoding("utf-8"); 

process.stdin.pipe(transform).pipe(process.stdout); 

После осмотра, transform в первом случае имеет кодирование нуля, тогда как во втором он действительно изменился к "UTF-8". Тем не менее, кусок, переданный функции преобразования, по-прежнему является буфером. Я думал, что, установив кодировку toString(), метод можно пропустить, но это не так.

Я также попытался расширить метод read, как в примерах Readable и Duplex, но это запрещено.

Есть ли способ избавиться от toString()?

ответ

1

Вы правы. Использование Buffer#toString прямо в вашем методе _transform плохое. Тем не менее, setEncoding предназначен для использования читаемым потоком потребителями (то есть код, который читается из вашего потока преобразования). Вы используете , реализуя поток преобразования. Он не изменяет вход вашего метода _transform для вас.

Внутренне читаемые потоки используют StringDecoder, если пользователь активировал автоматическое декодирование. Вы также можете использовать его в своем методе преобразования.

Вот code comment объяснить, как это работает:

[StringDecoder] декодирует данный буфер и возвращает его в JS строку, которая гарантированно не содержит каких-либо частичных символов многобайтовой. Любой частичный символ, найденный в конце буфера, буферизируется и будет возвращен при повторном вызове записи с остальными байтами.

Итак, ваш пример можно переписать следующим образом:

var StringDecoder = require('string_decoder').StringDecoder 
const transform = require("stream").Transform({ 
    transform: function(chunk, encoding, next) { 
    if(!this.myStringDecoder) this.myStringDecoder = new StringDecoder('utf8') 
    this.push(this.myStringDecoder.write().toUpperCase()); 
    next(); 
    } 
}); 

process.stdin.pipe(transform).pipe(process.stdout); 
+0

Мой первый фрагмент кода работает как есть, так что не будет необходимости использовать StringDecoder непосредственно. Я просто озадачен тем, что документы говорят, что экземпляры Transform «реализуют как Readable, так и Writable интерфейсы», когда для того, что вы говорите, похоже, не так.StringDecoder делает точно противоположное тому, что рекомендуется для Readable – cortopy

+0

Ваш фрагмент работает, пока многобайтовые символы не разделены на разные фрагменты. Я рекомендую использовать строковый декодер для потоков преобразования, которые работают с текстом. Документы немного неоднозначны. Они просто заявляют: «Вызовите эту функцию, чтобы заставить поток возвращать» неизменяемые строки, но поскольку это секция * потребителя *, я думаю, ясно, что это не влияет на разработчиков. Что вы думаете о том, что StringDecoder делает это не рекомендуется? –

+0

Если вы также управляете потребляющим концом потока преобразования, вы можете вызвать 'setEncoding' на' process.stdin'. –

Смежные вопросы