将Node.js流的内容读入字符串变量

时间:2012-05-16 17:42:11

标签: javascript node.js stream

我正在攻击node.js程序,该程序捕获SMTP邮件并对邮件数据执行操作。 'smtp-protocol'节点库以流形式提供邮件数据,作为node.js新手,我不知道如何将该流写入字符串变量。我目前使用以下行写入stdout:

stream.pipe(process.stdout, { end : false });

正如我所说,我需要将此流数据写入字符串变量,然后在流结束后我将使用它。

非常感谢!

18 个答案:

答案 0 :(得分:51)

希望这比上面的答案(现在有一个断开的链接)更有用。

另请注意,字符串连接不是收集字符串部分的有效方法,但它是为了简单起见而使用(也许您的代码不关心效率)

var string = ''
stream.on('readable',function(buffer){
  var part = buffer.read().toString();
  string += part;
  console.log('stream data ' + part);
});


stream.on('end',function(){
 console.log('final output ' + string);
});

答案 1 :(得分:46)

以上都不适合我。我需要使用Buffer对象:

  const chunks = [];

  readStream.on("data", function (chunk) {
    chunks.push(chunk);
  });

  // Send the buffer or you can put it into a var
  readStream.on("end", function () {
    res.send(Buffer.concat(chunks));
  });

答案 2 :(得分:30)

另一种方法是将流转换为promise(请参阅下面的示例)并使用then(或await)将已解析的值分配给变量。

function streamToString (stream) {
  const chunks = []
  return new Promise((resolve, reject) => {
    stream.on('data', chunk => chunks.push(chunk))
    stream.on('error', reject)
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
  })
}

const result = await streamToString(stream)

答案 3 :(得分:28)

关键是要使用这两个Stream events

  • 事件:'数据'
  • 事件:'结束'

对于stream.on('data', ...),您应该将数据数据收集到缓冲区(如果是二进制)或字符串中。

对于on('end', ...),您应该使用已完成的缓冲区调用回调,或者如果您可以内联它并使用Promises库返回。

答案 4 :(得分:17)

我通常使用这个简单的函数将流转换为字符串:

function streamToString(stream, cb) {
  const chunks = [];
  stream.on('data', (chunk) => {
    chunks.push(chunk.toString());
  });
  stream.on('end', () => {
    cb(chunks.join(''));
  });
}

用法示例:

let stream = fs.createReadStream('./myFile.foo');
streamToString(stream, (data) => {
  console.log(data);  // data is now my string variable
});

答案 5 :(得分:9)

您对此有何看法?

import random
import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg


class MainWindowm(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindowm, self).__init__(*args, **kwargs)

        self.canvas = FigureCanvasQTAgg(Figure(figsize=(5, 4), dpi=100))
        self.setCentralWidget(self.canvas)

        self.axes = self.canvas.figure.subplots()

        n_data = 50
        self.xdata = list(range(n_data))
        self.ydata = [random.randint(0, 10) for i in range(n_data)]

        self.serial_port = QtSerialPort.QSerialPort("COM3")
        self.serial_port.setBaudRate(QtSerialPort.QSerialPort.Baud9600)
        self.serial_port.errorOccurred.connect(self.handle_error)
        self.serial_port.readyRead.connect(self.handle_ready_read)
        self.serial_port.open(QtCore.QIODevice.ReadWrite)

    def handle_ready_read(self):
        while self.serial_port.canReadLine():
            codec = QtCore.QTextCodec.codecForName("UTF-8")
            line = codec.toUnicode(self.serial_port.readLine()).strip().strip('\x00')
            try:
                print(line)
                value = float(line)
            except ValueError as e:
                print("error", e)
            else:
                self.update_plot(value)

    def handle_error(self, error):
        if error == QtSerialPort.QSerialPort.NoError:
            return
        print(error, self.serial_port.errorString())

    def update_plot(self, value):
        self.ydata = self.ydata[1:] + [value]
        self.axes.cla()
        self.axes.plot(self.xdata, self.ydata, "r")
        self.canvas.draw()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindowm()
    w.show()

    sys.exit(app.exec_())

答案 6 :(得分:7)

从nodejs documentation你应该这样做 - 总是记住一个字符串而不知道编码只是一堆字节:

var readable = getReadableStreamSomehow();
readable.setEncoding('utf8');
readable.on('data', function(chunk) {
  assert.equal(typeof chunk, 'string');
  console.log('got %d characters of string data', chunk.length);
})

答案 7 :(得分:6)

Streams没有简单的.toString()函数(我理解),也没有.toStringAsync(cb)函数(我不明白)。

所以我创建了自己的辅助函数:

var streamToString = function(stream, callback) {
  var str = '';
  stream.on('data', function(chunk) {
    str += chunk;
  });
  stream.on('end', function() {
    callback(str);
  });
}

// how to use:
streamToString(myStream, function(myStr) {
  console.log(myStr);
});

答案 8 :(得分:4)

轻松使用流行的(每周下载量超过500万)和轻量级的获取流库:

https://www.npmjs.com/package/get-stream

const fs = require('fs');
const getStream = require('get-stream');

(async () => {
    const stream = fs.createReadStream('unicorn.txt');
    console.log(await getStream(stream)); //output is string
})();

答案 9 :(得分:3)

我有这样的运气:

template<template<class, size_t> class P, class T, size_t i>
P<T, i - 1> my_func(const P<T, i> & my_P);

int main()
{
    A<int, 10> a;
    B<char, 3> b;
    C<double, 7> c;

    auto smaller_a = my_func(a); // is a A<int, 9>
    auto smaller_b = my_func(b); // is a B<char, 2>
    auto smaller_c = my_func(c); // is a C<double, 6>
}

我使用节点let string = ''; readstream .on('data', (buf) => string += buf.toString()) .on('end', () => console.log(string)); v9.11.1是来自readstream回调的响应。

答案 10 :(得分:3)

还有一个使用promise的字符串:

function getStream(stream) {
  return new Promise(resolve => {
    const chunks = [];

    stream.on("data", chunk => chunks.push(chunk));
    stream.on("end", () => resolve(Buffer.concat(chunks).toString()));
  });
}

用法:

const stream = fs.createReadStream(__filename);
getStream(stream).then(r=>console.log(r));

如有必要,删除.toString()以用于二进制数据。

答案 11 :(得分:2)

像流减速器这样的东西呢?

以下是使用ES6类的示例如何使用。

var stream = require('stream')

class StreamReducer extends stream.Writable {
  constructor(chunkReducer, initialvalue, cb) {
    super();
    this.reducer = chunkReducer;
    this.accumulator = initialvalue;
    this.cb = cb;
  }
  _write(chunk, enc, next) {
    this.accumulator = this.reducer(this.accumulator, chunk);
    next();
  }
  end() {
    this.cb(null, this.accumulator)
  }
}

// just a test stream
class EmitterStream extends stream.Readable {
  constructor(chunks) {
    super();
    this.chunks = chunks;
  }
  _read() {
    this.chunks.forEach(function (chunk) { 
        this.push(chunk);
    }.bind(this));
    this.push(null);
  }
}

// just transform the strings into buffer as we would get from fs stream or http request stream
(new EmitterStream(
  ["hello ", "world !"]
  .map(function(str) {
     return Buffer.from(str, 'utf8');
  })
)).pipe(new StreamReducer(
  function (acc, v) {
    acc.push(v);
    return acc;
  },
  [],
  function(err, chunks) {
    console.log(Buffer.concat(chunks).toString('utf8'));
  })
);

答案 12 :(得分:2)

最干净的解决方案可能是使用&#34; string-stream&#34; package,它将流转换为带有promise的字符串。

const streamString = require('stream-string')

streamString(myStream).then(string_variable => {
    // myStream was converted to a string, and that string is stored in string_variable
    console.log(string_variable)

}).catch(err => {
     // myStream emitted an error event (err), so the promise from stream-string was rejected
    throw err
})

答案 13 :(得分:1)

列出的所有答案似乎都是在流动模式下打开“可读流”,这不是NodeJS的默认设置,并且由于缺少NodeJS在“暂停的可读流”模式下提供的反压支持,因此存在局限性。 这是使用Just Buffer,本机流和本机流转换的实现,并支持对象模式

import {Transform} from 'stream';

let buffer =null;    

function objectifyStream() {
    return new Transform({
        objectMode: true,
        transform: function(chunk, encoding, next) {

            if (!buffer) {
                buffer = Buffer.from([...chunk]);
            } else {
                buffer = Buffer.from([...buffer, ...chunk]);
            }
            next(null, buffer);
        }
    });
}

process.stdin.pipe(objectifyStream()).process.stdout

答案 14 :(得分:0)

这对我有用,并且基于Node v6.7.0 docs

let output = '';
stream.on('readable', function() {
    let read = stream.read();
    if (read !== null) {
        // New stream data is available
        output += read.toString();
    } else {
        // Stream is now finished when read is null.
        // You can callback here e.g.:
        callback(null, output);
    }
});

stream.on('error', function(err) {
  callback(err, null);
})

答案 15 :(得分:0)

使用您可能已经在项目依赖项中使用的quite popular stream-buffers package,这非常简单:

// imports
const { WritableStreamBuffer } = require('stream-buffers');
const { promisify } = require('util');
const { createReadStream } = require('fs');
const pipeline = promisify(require('stream').pipeline);

// sample stream
let stream = createReadStream('/etc/hosts');

// pipeline the stream into a buffer, and print the contents when done
let buf = new WritableStreamBuffer();
pipeline(stream, buf).then(() => console.log(buf.getContents().toString()));

答案 16 :(得分:0)

setEncoding('utf8');

上面的塞巴斯蒂安·J做得很好。

我遇到了带有一些测试代码的“缓冲区问题”,并添加了编码信息并解决了该问题,请参见下文。

演示问题

软件

// process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
    console.log(typeof(data), data);
});

输入

hello world

输出

object <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a>

演示解决方案

软件

process.stdin.setEncoding('utf8'); // <- Activate!
process.stdin.on('data', (data) => {
    console.log(typeof(data), data);
});

输入

hello world

输出

string hello world

答案 17 :(得分:0)

就我而言,内容类型响应标头为 Content-Type:文本/纯文本。因此,我已经从Buffer中读取了数据,例如:

let data = [];
stream.on('data', (chunk) => {
 console.log(Buffer.from(chunk).toString())
 data.push(Buffer.from(chunk).toString())
});