繁体   English   中英

如何从 Node.Js 中的字符串创建流?

[英]How to create streams from string in Node.Js?

我正在使用一个库ya-csv ,它需要一个文件或一个流作为输入,但我有一个字符串。

如何将该字符串转换为 Node 中的流?

作为@substack纠正我#node ,新的流API在节点V10使这更容易:

const Readable = require('stream').Readable;
const s = new Readable();
s._read = () => {}; // redundant? see update below
s.push('your text here');
s.push(null);

……之后,您可以自由地将其通过管道传输或以其他方式将其传递给您的目标消费者。

它不像恢复单行那样干净,但它确实避免了额外的依赖。

更新:到目前为止,在 v0.10.26 到 v9.2.1 中,如果您没有设置_read直接从 REPL 提示调用push将因not implemented异常而崩溃。它不会在函数或脚本内崩溃。如果不一致让您感到紧张,请包含noop 。)

不要使用 Jo Liss 的简历答案。 它在大多数情况下都可以工作,但在我的情况下,它让我失去了 4 或 5 个小时的错误查找时间。 不需要第三方模块来执行此操作。

新答案

var Readable = require('stream').Readable

var s = new Readable()
s.push('beep')    // the string you want
s.push(null)      // indicates end-of-file basically - the end of the stream

这应该是一个完全兼容的可读流。 有关如何正确使用流的更多信息,请参见此处

旧答案:只需使用本机 PassThrough 流:

var stream = require("stream")
var a = new stream.PassThrough()
a.write("your string")
a.end()

a.pipe(process.stdout) // piping will work as normal
/*stream.on('data', function(x) {
   // using the 'data' event works too
   console.log('data '+x)
})*/
/*setTimeout(function() {
   // you can even pipe after the scheduler has had time to do other things
   a.pipe(process.stdout) 
},100)*/

a.on('end', function() {
    console.log('ended') // the end event will be called properly
})

请注意,不会发出 'close' 事件(流接口不需要)。

从节点 10.17 开始,stream.Readable 有一个from方法可以轻松地从任何可迭代对象(包括数组文字)创建流:

const { Readable } = require("stream")

const readable = Readable.from(["input string"])

readable.on("data", (chunk) => {
  console.log(chunk) // will be called once with `"input string"`
})

请注意,至少在 10.17 和 12.3 之间,字符串本身是可迭代的,因此Readable.from("input string")将起作用,但每个字符发出一个事件。 Readable.from(["input string"])将为数组中的每一项(在本例中为一项Readable.from(["input string"])发出一个事件。

另请注意,在以后的节点中(可能是 12.3,因为文档说当时函数已更改),不再需要将字符串包装在数组中。

https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options

只需创建stream模块的新实例并根据您的需要对其进行自定义:

var Stream = require('stream');
var stream = new Stream();

stream.pipe = function(dest) {
  dest.write('your string');
  return dest;
};

stream.pipe(process.stdout); // in this case the terminal, change to ya-csv

要么

var Stream = require('stream');
var stream = new Stream();

stream.on('data', function(data) {
  process.stdout.write(data); // change process.stdout to ya-csv
});

stream.emit('data', 'this is my string');

编辑: 加思的答案可能更好。

我的旧答案文本保留在下面。


将一个字符串转换成流,你可以使用一个暂停通过流:

through().pause().queue('your string').end()

例子:

var through = require('through')

// Create a paused stream and buffer some data into it:
var stream = through().pause().queue('your string').end()

// Pass stream around:
callback(null, stream)

// Now that a consumer has attached, remember to resume the stream:
stream.resume()

有一个模块: https : //www.npmjs.com/package/string-to-stream

var str = require('string-to-stream')
str('hi there').pipe(process.stdout) // => 'hi there' 

另一种解决方案是将 read 函数传递给 Readable 的构造函数(参见 doc stream readeable options

var s = new Readable({read(size) {
    this.push("your string here")
    this.push(null)
  }});

例如,您可以在使用 s.pipe 之后

在咖啡脚本中:

class StringStream extends Readable
  constructor: (@str) ->
    super()

  _read: (size) ->
    @push @str
    @push null

用它:

new StringStream('text here').pipe(stream1).pipe(stream2)

我厌倦了每六个月重新学习一次,所以我刚刚发布了一个 npm 模块来抽象出实现细节:

https://www.npmjs.com/package/streamify-string

这是模块的核心:

const Readable = require('stream').Readable;
const util     = require('util');

function Streamify(str, options) {

  if (! (this instanceof Streamify)) {
    return new Streamify(str, options);
  }

  Readable.call(this, options);
  this.str = str;
}

util.inherits(Streamify, Readable);

Streamify.prototype._read = function (size) {

  var chunk = this.str.slice(0, size);

  if (chunk) {
    this.str = this.str.slice(size);
    this.push(chunk);
  }

  else {
    this.push(null);
  }

};

module.exports = Streamify;

str是调用时必须传递给构造函数的string ,并将由流作为数据输出。 options是可以被传递到一个流,每典型的选项的文档

根据 Travis CI,它应该与大多数版本的节点兼容。

这是 TypeScript 中的一个整洁的解决方案:

import { Readable } from 'stream'

class ReadableString extends Readable {
    private sent = false

    constructor(
        private str: string
    ) {
        super();
    }

    _read() {
        if (!this.sent) {
            this.push(Buffer.from(this.str));
            this.sent = true
        }
        else {
            this.push(null)
        }
    }
}

const stringStream = new ReadableString('string to be streamed...')

JavaScript 是鸭子类型的,所以如果你只是复制一个可读流的 API ,它会工作得很好。 事实上,您可能无法实现其中的大部分方法,或者只是将它们保留为存根; 您需要实现的只是库使用的内容。 您也可以使用 Node 的预构建EventEmitter来处理事件,因此您不必自己实现addListener等。

以下是在 CoffeeScript 中实现它的方法:

class StringStream extends require('events').EventEmitter
  constructor: (@string) -> super()

  readable: true
  writable: false

  setEncoding: -> throw 'not implemented'
  pause: ->    # nothing to do
  resume: ->   # nothing to do
  destroy: ->  # nothing to do
  pipe: -> throw 'not implemented'

  send: ->
    @emit 'data', @string
    @emit 'end'

然后你可以像这样使用它:

stream = new StringStream someString
doSomethingWith stream
stream.send()

在 NodeJS 中,您可以通过以下几种方式创建可读流:

解决方案 1

您可以使用fs模块来完成。 函数fs.createReadStream()允许您打开一个可读流,您所要做的就是传递文件的路径以开始流式传输。

const fs = require('fs');

const readable_stream = fs.createReadStream('file_path');

解决方案 2

如果你不想创建文件,你可以创建一个内存流并用它做一些事情(例如,将它上传到某个地方)。 您可以使用stream模块执行此操作。 您可以从stream模块导入Readable并创建可读流。 创建对象时,还可以实现read()方法,用于从内部缓冲区读取数据。 如果没有可供读取的数据,则返回null 可选的size参数指定要读取的特定字节数。 如果未指定size参数,则将返回内部缓冲区中包含的所有数据。

const Readable = require('stream').Readable;

const readable_stream = new Readable({
  ​read(size) {
   ​// ...
​  }
});

解决方案 3

当您通过网络获取某些内容时,可以像流一样获取(例如,您正在从某个 API 获取 PDF 文档)。

const axios = require('axios');

const readable_stream = await axios({
  method: 'get',
  url: "pdf_resource_url",
  responseType: 'stream'
}).data;

解决方案 4

第三方包可以支持创建流作为功能。 这是aws-sdk包的一种方式,通常用于将文件上传到S3

const file = await s3.getObject(params).createReadStream();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM