将stream缓冲区转换为utf8string
我想使用node.js从Web服务器加载一些文本来发出HTTP请求。 由于响应可以包含很多文本(几兆字节),我想分别处理每个文本块。 我可以使用下面的代码来实现这个function:
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, sb }); 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')
就像上面的第一个示例代码中的非压缩数据不适合我的需要。
单缓冲区
如果你有一个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 }); });
stream式缓冲区
如果在上面的问题中,像第一个Buffer
(块)中包含多字节UTF8-字符的第一个字节,而第二个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
缓冲,直到所有需要的字节被写入解码器。
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); });