【问题标题】:How to get chunks from a stream obtained from a string not from a file (Node.js)如何从从字符串而不是从文件中获取的流中获取块(Node.js)
【发布时间】:2017-10-02 01:04:45
【问题描述】:

在 Node.js 中对文件使用 fs.createReadStream 方法时,我得到一个可读流,在该流上发出“数据”事件。所以,稍后我可以调用 myReadableStream.on('data', (chunk) => { ... } ),在那里我可以获得流的块,因此它不会使内存过热。问题是,当从字符串而不是文件创建流时,如何将流拆分为块?现在,我有一个字符串,我使用 require('stream').Readable 将其转换为可读对象,但是当我调用 on('data') 时,我只得到 1 个块(我假设没有 'data' 事件在转换为可读流的字符串上发出,不是吗?)。从文件派生的流的值和从字符串派生的流的值是相同的(相同的长度),所以我希望它被很好地分成几个块以加快数据处理。有人可以帮忙吗?

【问题讨论】:

    标签: node.js


    【解决方案1】:

    我想我已经回答了我的问题。

    为了从文件中读取,我使用了

    fs.createReadStream(path[, options])
    

    方法返回一个新的 ReadStream 对象 (doc)。

    Node.js 中有 4 种类型的流(Readable、Writable、Duples 和 Transform)(doc)。可读流和可写流都将数据存储在内部缓冲区中。可能缓冲的数据量取决于传递给流构造函数的 highWaterMark 选项。

    对于普通流(从字符串或缓冲区对象构建的流),highWaterMark 选项指定总字节数。对于在对象模式下运行的流(基于 Javascript 对象的流),highWaterMark 指定对象的总数。

    Implementing a Readable stream 您可以看到 highWaterMark 值默认为 16384 字节(或 16 KB)(对象模式下的流到 16 个对象),并且从fs.createReadStream(path[, options]) 方法你可以透露

    与在可读流 (16 kb) 上为 highWaterMark 设置的默认值不同,此方法返回的流具有相同参数的默认值 64 kb。

    因此,默认情况下 fs.createReadStream(path[, options] 方法返回的 ReadStream 对象的 highWaterMark 设置为 65536 字节 (64 KB)。

    现在我可以检查我的代码了。我存储到文件中的字符串大小为 7372801 字节。当我使用 fs.createReadStream(path[, options] 方法从这个文件中读取时,我得到 113 块:

    // To get a ReadStream object
    fs.open(path, 'r', (err, fd) => { // fd - file descriptor
       if (err) {
          if (err.code === 'ENOENT') {
             // path points to nowhere - file does not exist
          }
          throw err
       }
    
          var rStream = fs.createReadStream(path, {fd: fd})
    })
    

    顺便说一句,在这里我使用文件描述符来读取文件。来自文档:

    如果指定了 fd,ReadStream 将忽略路径参数并使用指定的文件描述符。这意味着不会发出“打开”事件。注意 fd 应该是阻塞的;非阻塞 fds 应该传递给 net.Socket。

    // To get number of chunks
    var counter = 0
    
    rStream.on('data', (chunk) => {
       counter++
    })
    
    rStream.on('end', () => {
       console.log('Total number of chunks: ' + counter)
    }) 
    

    这是因为 7372801 / 65538 (64 KB) = 112 + 余数 => 113 当我人为地将字符串转换为流时(您可以在文档的实现流部分中找到如何执行此操作的信息,在我的示例中,我创建了一个单独的类):

    const Readable = require('stream').Readable;
    const util = require('util');
    
    function MyReadable(str, options) {
       if (!(this instanceof MyReadable))
          return new MyReadable(str, options);
       Readable.call(this, options);
       this.str = str;
    }
    util.inherits(MyReadable, Readable);
    
    MyReadable.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 = MyReadable; 
    
    // Then 
    var MyReadable = require('./filename')
    var stream = new MyReadable(myString, {highWaterMark: 65536} ) // highWaterMark is in bytes
    

    自从我将 highWaterMark 选项重新设置为 64KB 后,上述流也提供了 113 个块。

    在 Node.js 中,要获取字符串中的字节数,可以使用Buffer.byteLength(string[, encoding]) 方法。编码默认为“utf8”。

    要从可读流中获取缓冲区,您可以使用

    rStream._readableState.buffer
    

    来自可写流 ->

    wStream._writableState.getBuffer()
    

    所以,现在我可以使用 highWaterMark 选项来管理块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-06
      • 2011-06-30
      • 2019-06-06
      • 1970-01-01
      • 2013-06-24
      • 2017-08-26
      相关资源
      最近更新 更多