Чтение большого файла и метод splitby
Я пытаюсь использовать 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 ответ
Здесь действительно три проблемы.
- Чтение данных содержимого из файлов
- Извлечение разделенных кусков
- Получение результирующих данных из потока
Сначала вам нужно прочитать содержимое каждого файла. Обратите внимание, что завернутый 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
)