Я думаю, что я не реализую и не использую читаемый поток правильно и эффективно? - PullRequest
0 голосов
/ 23 июня 2018

Это программа, которая считывает данные из текстового файла 'IN.txt' и записывает их в файл 'copy.json' в формате json.
В каждой строке текстового файла слова разделяются табуляцией, и с помощью табуляции я разбиваю строку на массив

Я думаю, что реализация читаемого потока таким образом перезаписывает одни и те же фрагменты данных снова и снова, что неэффективно для больших файлов.
Я пробовал много разных способов, но я получал ошибки, такие как утечка памяти, _читальный метод не определен и т. Д.

const fs = require('fs');
const readLine = require('readline');
const { Readable } = require('stream');
const dataArray = [];

//creating readline interface
const lineReader = readLine.createInterface({
    input: fs.createReadStream(__dirname + '/IN.txt'),
});

const fields = ['country', 'pin', 'place', 'state', 'code', 'division', 'admin', 'mandal', 'xxx', 'lat', 'long'];

//reading data from text file line by line and spliting each line into array
lineReader.on('line', function (line) {
    let words = line.split('\t');
    writeToFile(fields, words);
});

lineReader.on('close', function (line) {
    console.log('***Finished***');
    process.exit(0);
});

//words array will be like ["IN","744301", "Mus Andaman & Nicobar Islands", "01 Nicobar 638 Carnicobar" , "9.2333", "92.7833","4"]
//creating obj with fields and words array and pushing into array
function writeToFile(fields, words) {
    var obj = {};
    for(let i = 0; i < fields.length; i++) {
        obj[fields[i]] = words[i];
    }
    dataArray.push(obj);
    //implementing readable stream and pushing string into it 
    const rStream = new Readable();
    rStream.push(JSON.stringify(dataArray, null, 4));
    rStream.push(null);
    const output = fs.createWriteStream(__dirname + '/copy.json');
    //piping to output
    rStream.pipe(output);
}

вот небольшой снимок файла IN.txt

IN.txt файл

1 Ответ

0 голосов
/ 23 июня 2018

При каждом вызове writeToFile (в основном при чтении каждой строки) вы создаете readStream и копируете в него dataArray, отправляя по трубопроводу в поток записи.Вам это не нужно, если у вас уже есть поток чтения, открытый для файла.

Хороший текст для чтения: https://medium.freecodecamp.org/node-js-streams-everything-you-need-to-know-c9141306be93

Дайте следующую попытку: process.memoryUsage().heapUsed / 1024 / 1024 далиМоя куча памяти используется как около 147 МБ для файла IN.txt размером около 14 МБ.

const fs = require('fs');
const readLine = require('readline');
const { Readable } = require('stream');
const output = fs.createWriteStream(__dirname + '/copy.json');
const dataArray = [];

//creating readline interface
const lineReader = readLine.createInterface({
    input: fs.createReadStream(__dirname + '/IN.txt')
});

const fields = ['country', 'pin', 'place', 'state', 'code', 'division',     'admin', 'mandal', 'xxx', 'lat', 'long'];

//reading data from text file line by line and pushing it to an array
lineReader.on('line', function (line) {
    let words = line.split('\t');
    dataArray.push(getLineContent(fields, words));
});

lineReader.on('close', function (line) {
    console.log('***Finished***');
    output.write(JSON.stringify(dataArray, null, 4));
    output.end();
    process.exit(0);
});

//words array will be like ["IN","744301", "Mus Andaman & Nicobar Islands", "01 Nicobar 638 Carnicobar" , "9.2333", "92.7833","4"]
//creating obj with fields and words
function getLineContent(fields, words) {
    var obj = {};
    for(let i = 0; i < fields.length; i++) {
        obj[fields[i]] = words[i];
    }
    return obj;
}

Более эффективное решение:

process.memoryUsage().heapUsed / 1024 / 1024 дает мне кучу памяти, используемую как около 5-7 МБ (значительное улучшение по сравнению с описанным выше подходом) для файла IN.txt размером около 14 МБ.

Подробнее Справочный текст:

  1. Недопонимание потока HighWaterMark
  2. Приостановка readline в Node.js
  3. https://www.valentinog.com/blog/memory-usage-node-js/

Следующее может помочь вам дать толчок:

const fs = require('fs');
const readLine = require('readline');
const { Readable } = require('stream');
const output = fs.createWriteStream(__dirname + '/copy.json');

//creating readline interface
const lineReader = readLine.createInterface({
    input: fs.createReadStream(__dirname + '/IN.txt')
});

const fields = ['country', 'pin', 'place', 'state', 'code', 'division',         'admin', 'mandal', 'xxx', 'lat', 'long'];

let lineCount = 0;
let writeAllowed = true; //Turns to false when stream.write starts     returning false
let paused = false; //Pause Readline
let buffstr = ""; //To handle leaks after calling readLine pause()

//reading data from text file line by line and pushing it to an array
lineReader.on('line', function (line) {
    lineCount++;
    let words = line.split('\t');
    let lineJson = getLineContent(fields, words);

    if (paused) {
      if(lineCount > 1) {
        buffstr = buffstr + ",";
      }
      buffstr = buffstr + JSON.stringify(lineJson, null, 4);
    }
    else {
      if(!writeAllowed) {
        lineReader.pause();
      }
      lineCount === 1 ? writeMe('[') : writeMe(",");
      writeMe(JSON.stringify(lineJson, null, 4));
    }
});

lineReader.on('pause', function() {
   paused = true;
});

lineReader.on('resume', function() {
   paused = false;
});

lineReader.on('close', function (line) {
    output.write(buffstr);
    output.write(']');
    output.end();
    console.log(`***Finished*** Memory heap used:     ${process.memoryUsage().heapUsed / 1024 / 1024} MB`);
});

function writeMe(str){
   if(writeAllowed){
      writeAllowed = writeAllowed && output.write(str);
   }
   else{
      buffstr += str;
      output.once('drain', function() {
         lineReader.resume();
         output.write(buffstr);
         buffstr = ""; //Possible scope of improvement. Need to check if     any race condition
         writeAllowed = true;
      });
   }
}

//words array will be like ["IN","744301", "Mus Andaman & Nicobar     Islands", "01 Nicobar 638 Carnicobar" , "9.2333", "92.7833","4"]
//creating obj with fields and words
function getLineContent(fields, words) {
    var obj = {};
    for(let i = 0; i < fields.length; i++) {
        obj[fields[i]] = words[i];
    }
    return obj;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...