On Node.js we can read a file line by line using the readline module:
var fs = require('fs');
var readline = require('readline');
var rl = readline.createInterface({
input: fs.createReadStream('filepath');
});
rl.on('line', function(line) {
console.log(`Line read: ${line}`);
});
But what if we want to start reading on a specific line number? I know that when we use the createReadStream we can pass in a start parameter. This is explained in the docs:
options can include start and end values to read a range of bytes from the file instead of the entire file.
But here start is one offset in bytes, so it seems complicated to use this to set the starting line.
How can we adapt this approach to start reading a file on a specific line?
You have to read the file from the beginning and count lines and start processing the lines only after you get to a certain line. There is no way to have the file system tell you where a specific line starts.
var fs = require('fs');
var readline = require('readline');
var cntr = 0;
var rl = readline.createInterface({
input: fs.createReadStream('filepath');
});
rl.on('line', function(line) {
if (cntr++ >= 100) {
// only output lines starting with the 100th line
console.log(`Line read: ${line}`);
}
});
Related
I am working on a sales tax problem with node js and I am trying to read text from a file input.txt then calculate the taxes and prices as a final output.
I used the function below to read the file input.txt line by line and it's working
var fs = require('fs'),
readline = require('readline');
var rl = readline.createInterface({
input : fs.createReadStream('input.txt'),
output: process.stdout,
terminal: false
})
rl.on('line',function(line){
console.log(line)
})
But the problem is when I tried use the function scanProduct() on that text it didn't work.
This is the whole code
var Cart = require('./src/Cart');
var cart1 = new Cart();
var cart2 = new Cart();
var cart3 = new Cart();
cart1.scanProduct('1 book at 12.49');
cart1.scanProduct('1 music CD at 14.99');
cart1.scanProduct('1 chocolate bar at 0.85');
cart2.scanProduct('1 imported box of chocolates at 10.00');
cart2.scanProduct('1 imported bottle of perfume at 47.50');
// cart3.scanProduct('1 imported bottle of perfume at 27.99');
// cart3.scanProduct('1 bottle of perfume at 18.99');
// cart3.scanProduct('1 packet of headache pills at 9.75');
// cart3.scanProduct('1 box of imported chocolates at 11.25');
var fs = require('fs'),
readline = require('readline');
var rl = readline.createInterface({
input : fs.createReadStream('input.txt'),
output: process.stdout,
terminal: false
})
rl.on('line',function(line){
//console.log(line)
cart3.scanProduct(line)
})
console.log(cart1.bill());
console.log("\n");
console.log(cart2.bill());
console.log("\n");
console.log(cart3.bill());
scanProduct() and bill() are fuction used to calculate taxes and give the final output and it's working in cart1 and car2 that way. When I tried to get text from the file it didn't work.
It fails because reading of a file is an asynchronous operation and cart3.bill()
function is called before cart3.scanProduct(line) function.
You should listen to an 'end' event of a readable stream then call the cart3.bill() function.
Like this:
rl.on('end',function(){
console.log(cart3.bill());
})
I was running code from here:
https://nodejs.org/dist/latest-v10.x/docs/api/readline.html#readline_example_read_file_stream_line_by_line
const fs = require('fs');
const readline = require('readline');
async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
}
}
processLineByLine();
and got this warning:
(node:13735) ExperimentalWarning: readline Interface [Symbol.asyncIterator] is an experimental feature. This feature could change at any time
(node:13735) ExperimentalWarning: Readable[Symbol.asyncIterator] is an experimental feature. This feature could change at any time
What is experimental exactly? There is no line number.
It says:
readline Interface [Symbol.asyncIterator]
So look for an interface:
const rl = readline.createInterface
that you are iterating over:
const line of rl
I want to dynamically change the content of a element in my html page during nodejs readline process.
Here is a jsfiddle example to shown the display effect I want to fulfill:
https://jsfiddle.net/09kuyn7v/
But I want to dynamically display lines from my local file, but not from an array defined within the function as in the jsfiddle example.
I have used readline module in my read-file-version clickTest() function:
function clickTest(){
var fs = require('fs');
var lineReader = require('readline').createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
document.getElementById("demo").innerHTML += line;
});
}
But when I click the button, the page was just like being freezed and then the lines were displayed simultaneously (not one by one as shown in the jsfiddle example above).
First of all, every time you call that function you do require('readline') and require('fs') so I would move that up the script.
I would suggest two approaches:
Pausing read
var readline = require('readline');
var fs = require('fs');
function clickTest(){
var lineReader = readline.createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
// pause emitting of lines...
lineReader.pause();
// write line to dom
document.getElementById("demo").innerHTML += line;
// Resume after some time
setTimeout(function(){
lineReader.resume();
}, 1000);
});
lineReader.on('end', function(){
lineReader.close();
});
}
This approach should read one line, then pause and resume after some time you specify.
Buffering lines
var readline = require('readline');
var fs = require('fs');
var lines = [];
function clickTest(){
var lineReader = readline.createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
lines.push(line)
});
lineReader.on('end', function(){
lineReader.close();
printLine(0);
});
}
function printLine(index){
// write line to dom
document.getElementById("demo").innerHTML += lines[index];
if (index < lines.length - 1){
setTimeout(function(){
printLine(index + 1);
}, 1000);
}
}
This approach will save all the lines into an array and then slowly prints them out.
Please note that I haven't got node-webkit to actually test it, so you might find a bug in the code, but it should give you general idea
I am trying to write a program in Haskell that takes in the input as a string of sentences, calls a javascript file with that input, and return the output of that javascript file as the output of the Haskell file. Right now, the output of the javascript file is not printed. It is not clear whether javascript file is called or not.
Here is the script in Haskell:
main :: IO ()
main =
do
putStrLn "Give me the paragraphs \n"
paragraphs <- getLine
output <- readCreateProcess (shell "node try2.js") paragraphs
putStrLn output
Script in Node.js. The desired output is toplines:
var lexrank = require('./lexrank');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Hi', (answer) => {
var originalText = answer;
var topLines = lexrank.summarize(originalText, 5, function (err, toplines, text) {
if (err) {
console.log(err);
}
rl.write(toplines);
// console.log(toplines);
});
rl.close();
});
I am guessing there is some problem with my way of doing stdin. I am new to Node.js
It took me a really long time but following code works:
Haskell File:
import System.Process
main :: IO ()
main =
do
putStrLn "Give me the paragraphs \n"
paragraphs <- getLine
output <- readCreateProcess (shell "node lexrankReceiver.js") (paragraphs ++ "\n")
putStrLn output
NodeJs File:
// Getting this to work took almost a full day. Javascript gets really freaky
// when using it on terminal.
/* Import necessary modules. */
var lexrank = require('./Lexrank/lexrank.js');
const readline = require('readline');
// var Type = require('type-of-is');
// var utf8 = require('utf8');
// Create readline interface, which needs to be closed in the end.
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Set stdin and stdout to be encoded in utf8. Haskell passes string as basic
// 8-bit unsigned integer array. The output also needs to be encoded so that
// Haskell can read them
process.stdin.setEncoding('utf8');
process.stdout.setEncoding('utf8');
// If a string is readable, start reading.
process.stdin.on('readable', () => {
var chunk = process.stdin.read();
if (chunk !== null) {
var originalText = chunk;
var topLines = lexrank.summarize(originalText, 5, function (err, toplines, text) {
if (err) {
console.log(err);
}
// Loop through the result to form a new paragraph consisted of most
// important sentences in ascending order. Had to split the 0 index and
// the rest indices otherwise the first thing in newParagraphs will be
// undefined.
var newParagraphs = (toplines[0])['text'];
for (var i = 1; i < toplines.length; i++) {
newParagraphs += (toplines[i])['text'];
}
console.log(newParagraphs);
});
}
});
// After the output is finished, set end of file.
// TODO: write a handler for end of writing output.
process.stdin.on('end', () => {
process.stdout.write('\n');
});
// It is incredibly important to close readline. Otherwise, input doesn't
// get sent out.
rl.close();
The problem with the Haskell program you have is that paragraphs is not a line of input, just a string, so to fix the issue you can append a newline, something like:
output <- readCreateProcess (shell "node try2.js") $ paragraphs ++ "\n"
To find this issue I tried replacing question with a shim:
rl.question = function(prompt, cb) {
rl.on('line', function(thing) {
console.log(prompt);
cb(thing);
})
}
And that worked, so I knew it was something to do with how question handles stdin. So after this I tried appending a newline and that worked. Which means question requires a 'line' of input, not just any string, unlike on('line'), oddly enough.
I was wondering if it was at all possible to read the very last line of a text file. And then, read the one before that. I can see all the data in the console, but I have no idea how to just display one line.
Currently, I am using fs and byline, to write and read files, respectively.
Use the readline core module instead of byline, and keep track of the current and previous lines when you receive events.
var rl = require('readline').createInterface({
input: require('fs').createReadStream('input.file')
});
var current = "";
var prev = "";
rl.on('line', function (line) {
prev = current;
current = line;
});
rl.on('close', function () {
console.log('Last line:', current);
console.log('Prev line:', prev);
});
Alternatively, just read the whole file into a string and then split it after line breaks.