Ускорить парсинг большого файла
Я только начал изучать NodeJS и наконец смог вывести окно с интерфейсом, а так же сделать выбор файла.. Цель была: При выборе файла пройтись по всем строкам и сделать с ними действия (соответствует регулярному выражению и т.д.) так же нужно было убрать дубли данных из строки (то есть, если уже была строка с такими данными - мы ее пропускаем). Я сделал массив и добавлял в него эти данные, а при новой строке я проверял через indexOf. В файле который нужно парсить больше 1.000.000 строк, занимает это очень много времени и мне необходимо как-то это ускорить. Я подозреваю, что узкое место - тот самый массив.
Для записи в новый файл строк, который прошли проверки я использую ( stream = fs.createWriteStream ) и внутри ( stream.write(...) ).
Из найденого в гугле способа чтения большого файла я остановился на этом:
fs.createReadStream(path.format(filePath))
.pipe(es.split())
.pipe(es.mapSync(line => { ... })
Цель: найти способ, который ускорит весь процесс.
const { ipcRenderer: ipc, remote: app } = require('electron');
const path = require('path');
const es = require('event-stream');
const fs = require('fs');
const selectFileBtn = document.querySelector('.selectFile__btn');
selectFileBtn.addEventListener('click', selectFile, false);
const parsingDeleted = document.querySelector('.parsing__deleted');
const parsingStatus = document.querySelector('.parsing__status');
const parsingDouble = document.querySelector('.parsing__double');
const parsingFile = document.querySelector('.parsing__file');
function selectFile()
{
app.dialog.showOpenDialog(
{
properties : ["openFile"],
title : 'Выбери файл для парсинга',
buttonLabel: 'Выбрать',
filters :
[
{name: 'Text file', extensions: ['txt']},
]
}
)
.then(data => data.filePaths)
.then(files =>
{
if (!files.length)
{
return;
}
let data = new Map();
let count = 0, count_double = 0;
let time = new Date().getTime();
let filePath = path.parse(files[0].split(String.fromCharCode(92)).join(String.fromCharCode(92,92)));
let fileSavedPath = `${filePath.dir}\\${filePath.name}__parsed${filePath.ext}`;
parsingFile.innerText = filePath.base;
parsingDeleted.innerText = count;
parsingDoble.innerText = count_double;
parsingStatus.innerText = `Обработка файла...`;
document.querySelector('.selectFile').style.display = 'none';
document.querySelector('.parsing').style.display = 'block';
let stream = fs.createWriteStream(fileSavedPath);
stream.once('open', fd =>
{
fs.createReadStream(path.format(filePath))
.pipe(es.split())
.pipe(es.mapSync(line =>
{
line = line.replace(/^\+/, '').replace(/;/g, ':');
if (!line || /[А-Яа-я]/.test(line) || !/[7-9]/.test(line.substr(0, 1)))
{
count++;
parsingDeleted.innerText = count;
return;
}
if (line.substr(0, 1) == 9)
{
line = '7' +line;
}
else if (line.substr(0, 1) == 8)
{
line = '7' +line.substr(1);
}
if (data.has(line.split(':')[1]))
{
count_double++;
parsingDouble.innerText = count_double;
return;
}
data.set(line.split(':')[1], 1);
stream.write(`${line}\n`);
})
.on('error', err =>
{
console.log('Ошибка', err);
})
.on('end', function()
{
stream.end();
parsingStatus.innerText = `Завершено`;
console.log(`Усее, прошло времени: ${new Date().getTime() - time}`);
console.log(`Удалено строк: ${count}`);
console.log(`Удалено дублей: ${count_double}`);
})
);
});
}
);
}
Ответы (1 шт):
Я сделал массив и добавлял в него эти данные, а при новой строке я проверял через indexOf.
Используйте Map. Поскольку эта структура намного быстрее ищет элемент.
const myMap = new Map();
const keyObj = {},
keyFunc = function () {},
keyString = 'a string';
// задание значений
myMap.set(keyString, 'value associated with “a string”');
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');
myMap.size; // 3
// получение значений
myMap.get(keyString); // value associated with “a string”
myMap.get(keyObj); // value associated with keyObj
myMap.get(keyFunc); // v