123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- 'use strict';
- const fs = require('fs');
- /**
- * @class
- */
- class LineByLine {
- constructor(file, options) {
- options = options || {};
- if (!options.readChunk) options.readChunk = 1024;
- if (!options.newLineCharacter) {
- options.newLineCharacter = 0x0a; //linux line ending
- } else {
- options.newLineCharacter = options.newLineCharacter.charCodeAt(0);
- }
- if (typeof file === 'number') {
- this.fd = file;
- } else {
- this.fd = fs.openSync(file, 'r');
- }
- this.options = options;
- this.newLineCharacter = options.newLineCharacter;
- this.reset();
- }
- _searchInBuffer(buffer, hexNeedle) {
- let found = -1;
- for (let i = 0; i <= buffer.length; i++) {
- let b_byte = buffer[i];
- if (b_byte === hexNeedle) {
- found = i;
- break;
- }
- }
- return found;
- }
- reset() {
- this.eofReached = false;
- this.linesCache = [];
- this.fdPosition = 0;
- }
- close() {
- fs.closeSync(this.fd);
- this.fd = null;
- }
- _extractLines(buffer) {
- let line;
- const lines = [];
- let bufferPosition = 0;
- let lastNewLineBufferPosition = 0;
- while (true) {
- let bufferPositionValue = buffer[bufferPosition++];
- if (bufferPositionValue === this.newLineCharacter) {
- line = buffer.slice(lastNewLineBufferPosition, bufferPosition);
- lines.push(line);
- lastNewLineBufferPosition = bufferPosition;
- } else if (bufferPositionValue === undefined) {
- break;
- }
- }
- let leftovers = buffer.slice(lastNewLineBufferPosition, bufferPosition);
- if (leftovers.length) {
- lines.push(leftovers);
- }
- return lines;
- };
- _readChunk(lineLeftovers) {
- let totalBytesRead = 0;
- let bytesRead;
- const buffers = [];
- do {
- const readBuffer = new Buffer(this.options.readChunk);
- bytesRead = fs.readSync(this.fd, readBuffer, 0, this.options.readChunk, this.fdPosition);
- totalBytesRead = totalBytesRead + bytesRead;
- this.fdPosition = this.fdPosition + bytesRead;
- buffers.push(readBuffer);
- } while (bytesRead && this._searchInBuffer(buffers[buffers.length-1], this.options.newLineCharacter) === -1);
- let bufferData = Buffer.concat(buffers);
- if (bytesRead < this.options.readChunk) {
- this.eofReached = true;
- bufferData = bufferData.slice(0, totalBytesRead);
- }
- if (totalBytesRead) {
- this.linesCache = this._extractLines(bufferData);
- if (lineLeftovers) {
- this.linesCache[0] = Buffer.concat([lineLeftovers, this.linesCache[0]]);
- }
- }
- return totalBytesRead;
- }
- next() {
- if (!this.fd) return false;
- let line = false;
- if (this.eofReached && this.linesCache.length === 0) {
- return line;
- }
- let bytesRead;
- if (!this.linesCache.length) {
- bytesRead = this._readChunk();
- }
- if (this.linesCache.length) {
- line = this.linesCache.shift();
- const lastLineCharacter = line[line.length-1];
- if (lastLineCharacter !== this.newLineCharacter) {
- bytesRead = this._readChunk(line);
- if (bytesRead) {
- line = this.linesCache.shift();
- }
- }
- }
- if (this.eofReached && this.linesCache.length === 0) {
- this.close();
- }
- if (line && line[line.length-1] === this.newLineCharacter) {
- line = line.slice(0, line.length-1);
- }
- return line;
- }
- }
- module.exports = LineByLine;
|