Конвертировать потоковые буферы в utf8-строку
Я хочу сделать HTTP-запрос с помощью node.js для загрузки некоторого текста с веб-сервера. Поскольку ответ может содержать много текста (некоторые мегабайты), я хочу обрабатывать каждый кусок текста отдельно. Я могу добиться этого, используя следующий код:
var req = http.request(reqOptions, function(res) {
...
res.setEncoding('utf8');
res.on('data', function(textChunk) {
// process utf8 text chunk
});
});
Это, кажется, работает без проблем. Однако я хочу поддерживать HTTP-сжатие, поэтому я использую zlib:
var zip = zlib.createUnzip();
// NO res.setEncoding('utf8') here since we need the raw bytes for zlib
res.on('data', function(chunk) {
// do something like checking the number of bytes downloaded
zip.write(chunk); // give the raw bytes to zlib, s.b.
});
zip.on('data', function(chunk) {
// convert chunk to utf8 text:
var textChunk = chunk.toString('utf8');
// process utf8 text chunk
});
Это может быть проблемой для многобайтовых символов, таких как '\u00c4'
, который состоит из двух байтов: 0xC3
и 0x84
. Если первый байт покрывается первым фрагментом (Buffer
), а второй - вторым куском, тогда chunk.toString('utf8')
будет выдавать неправильные символы в конце/начале текстового фрагмента. Как я могу избежать этого?
Подсказка: мне все еще нужен буфер (точнее, количество байтов в буфере), чтобы ограничить количество загруженных байтов. Поэтому использование res.setEncoding('utf8')
, как в первом примере кода выше для несжатых данных, не соответствует моим потребностям.
Ответы
Ответ 1
Одиночный буфер
Если у вас есть один Buffer
, вы можете использовать метод toString
, который преобразует все или часть двоичного содержимого в string с использованием определенной кодировки. По умолчанию используется utf8
, если вы не предоставляете параметр, но я явно установил кодировку в этом примере.
var req = http.request(reqOptions, function(res) {
...
res.on('data', function(chunk) {
var textChunk = chunk.toString('utf8');
// process utf8 text chunk
});
});
Потоковые буферы
Если у вас есть потоковые буферы, как в вопросе выше, где первый байт многобайтового utf8
-character может содержаться в первом Buffer
(chunk) и втором байте во втором Buffer
, тогда вы должны использовать StringDecoder
.
var StringDecoder = require('string_decoder').StringDecoder;
var req = http.request(reqOptions, function(res) {
...
var decoder = new StringDecoder('utf8');
res.on('data', function(chunk) {
var textChunk = decoder.write(chunk);
// process utf8 text chunk
});
});
Таким образом, байты незавершенных символов буферизуются с помощью StringDecoder
, пока все необходимые байты не будут записаны в декодер.
Ответ 2
var fs = require("fs");
function readFileLineByLine(filename, processline) {
var stream = fs.createReadStream(filename);
var s = "";
stream.on("data", function(data) {
s += data.toString('utf8');
var lines = s.split("\n");
for (var i = 0; i < lines.length - 1; i++)
processline(lines[i]);
s = lines[lines.length - 1];
});
stream.on("end",function() {
var lines = s.split("\n");
for (var i = 0; i < lines.length; i++)
processline(lines[i]);
});
}
var linenumber = 0;
readFileLineByLine(filename, function(line) {
console.log(++linenumber + " -- " + line);
});