读取大文件和拆分方法

时间:2016-09-14 22:07:04

标签: javascript node.js stream highland.js

我正在尝试使用splitby中的highland.js方法在开始和结束分隔符之间提取数据。

        -----BEGIN DATA-----
        MIIEzDCCArSgAwIBAgIVCugKYzMN5ra8zPWxYE8pUU9SxjYSMA0GCSqGSIb3DQEB
        CwUAMHAxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV
        BAcMB1dhcndpY2sxEDAOBgNVBAoMB0VudHJ1c3QxETAPBgNVBAsMCFBLSSBURUFN
        -----END DATA-----
        -----BEGIN DATA-----
        MIIETzCCAjegAwIBAgIVBShP2Mx74DZEyNKwYZZPGntRmSWnMA0GCSqGSIb3DQEB
        DQUAMHIxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV
        BAcMB1dhcndpY2sxDDAKBgNVBAoMA0lCTTERMA8GA1UECwwIUEtJIFRFQU0xGTAX
        5/62
        -----END DATA-----

我可以将文件读入这样的流:

        const readFile = _.wrapCallback(fs.readFile);
        stream = _(files).map(readFile).parallel(2);

        const blob = _(stream).splitBy('-----BEGIN DATA-----')

但是,我似乎无法弄清楚如何处理文件并提取我需要的数据。

1 个答案:

答案 0 :(得分:1)

这里有三个问题。

  1. 从文件中读取内容数据
  2. 提取分隔的块
  3. 从流中获取结果数据
  4. 首先,您需要阅读每个文件的内容。请注意,已包裹的readFile会发出Buffers,而不是Strings。要提取块,您需要将每个文件的内容转换为String。我假设文件编码为utf-8

    其次,您需要将数据与文本的其余部分分开。我假设您只需要在开始和结束分隔符之间的块,没有分隔符本身或可能在分隔符之外的任何内容,例如:

    -----BEGIN DATA-----
    MIIEzDCCArSgAwIBAgIVCugKYzMN5ra8zPWxYE8pUU9SxjYSMA0GCSqGSIb3DQEB
    CwUAMHAxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV
    BAcMB1dhcndpY2sxEDAOBgNVBAoMB0VudHJ1c3QxETAPBgNVBAsMCFBLSSBURUFN
    -----END DATA-----
    junky junk junk
    -----BEGIN DATA-----
    MIIETzCCAjegAwIBAgIVBShP2Mx74DZEyNKwYZZPGntRmSWnMA0GCSqGSIb3DQEB
    DQUAMHIxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV
    BAcMB1dhcndpY2sxDDAKBgNVBAoMA0lCTTERMA8GA1UECwwIUEtJIFRFQU0xGTAX
    5/62
    -----END DATA-----
    

    应该导致:

    [ '\nMIIEzDCCArSgAwIBAgIVCugKYzMN5ra8zPWxYE8pUU9SxjYSMA0GCSqGSIb3DQEB\nCwUAMHAxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV\nBAcMB1dhcndpY2sxEDAOBgNVBAoMB0VudHJ1c3QxETAPBgNVBAsMCFBLSSBURUFN\n'
    , '\nMIIETzCCAjegAwIBAgIVBShP2Mx74DZEyNKwYZZPGntRmSWnMA0GCSqGSIb3DQEB\nDQUAMHIxCzAJBgNVBAYTAkdCMRUwEwYDVQQIDAxXYXJ3aWNrc2hpcmUxEDAOBgNV\nBAcMB1dhcndpY2sxDDAKBgNVBAoMA0lCTTERMA8GA1UECwwIUEtJIFRFQU0xGTAX\n5/62\n'
    ]
    

    为了得到这个结果,我使用带有两个不匹配组的正则表达式作为分隔符,并使用匹配的数据组。首先,我提取分隔的块,然后删除分隔符。这可能效率不高,但应该做好。

    请注意,flatMap的回调将返回一个字符串数组。在这里使用map会产生一个数组流 - 每个文件一个。我们想要的是单个字符串流。这就是为什么flatMap`在这里使用的原因。

    最后,您需要让流动并从中获取数据。要执行此操作,您需要在流上调用使用方法。在此示例中,我使用toArray。提供给此方法的回调将使用包含流的所有元素的数组调用 - 在本例中为所有数据块。

    以下是完整的内容:

    const Stream = require("highland")
    const FS = require("fs")
    
    const files = [ "./input-1.txt", "./input-2.txt"  ]
    const readFile = Stream.wrapCallback(FS.readFile);
    
    const pattern = /(?:-----BEGIN DATA-----)((.|\n)+?)(?:-----END DATA-----)/gm
    
    Stream(files)
      // 1. Read contents
      .map(readFile)
      .parallel(2)
      .invoke("toString", ["utf-8"])
      // 2. Process contents to extract data
      .flatMap((content) =>
        content
          // get an array of chunks (including delimiters)
          .match(pattern)
          // remove the delimiters from each chunk, leaving only the data
          .map((chunk) => chunk.replace(pattern, "$1")))
      // 3. Get the resulting data out of the stream
      .toArray((chunks) => 
        console.log(chunks) // will print an array of data chunks
      )