I am trying to write a program, where I need to read data from a file line by line synchronously, store values line by line in an array using Array.push(). I am reading the file using the readline npm package. However, when I try to call the array after iterating through the whole file, it shows me an empty array.
var fs = require('fs'),
readline = require('readline'),
stream = require('stream');
var instream = fs.createReadStream('sample.txt');
var outstream = new stream;
outstream.readable = true;
outstream.writable = true;
function printArray(ArrayVar){
console.log(ArrayVar);
}
function AddText(InputStream){
var Text = new Array;
var rl = readline.createInterface({
input: instream,
output: outstream,
terminal: false
});
rl.on('line',function(line){
Text.push(line);
});
return Text;
}
var a = AddText(instream);
printArray(a);
I think I am having a problem because of the asynchronous execution of this code. How can I fix this and print the content of the array in proper order as in the text file?
You need to listen to the close event and then print the array. close will be called once all lines have been read.
rl.on('close', function() {
console.log(Text)
});
Also,
var Text = new Array;
Should be:
var Text = new Array();
or
var Text = [];
You have to wait for the lines to be read before logging the variable(in your case its Text) value.
You must wait for all the lines to be read by listening on close event, or do something in line event itself.
Your code should look something like below
var fs = require('fs'),
readline = require('readline'),
stream = require('stream');
var instream = fs.createReadStream('sample.txt');
var outstream = new stream;
outstream.readable = true;
outstream.writable = true;
function printArray(ArrayVar){
console.log(ArrayVar);
}
function AddText(InputStream){
var Text = new Array;
var rl = readline.createInterface({
input: instream,
output: outstream,
terminal: false
});
rl.on('line',function(line){
Text.push(line);
});
rl.on('close', function(){
printArray(Text)
})
}
var a = AddText(instream);
Also you are not using the parameter InputStream that you are passing to AddText function.
Related
For some reason I'm having such a hard time converting this txt file to an actual javascript array.
myJson.txt
{"action": "key press", "timestamp": 1523783621, "user": "neovim"}
{"action": "unlike", "timestamp": 1523784584, "user": "r00k"}
{"action": "touch", "timestamp": 1523784963, "user": "eevee"}
{"action": "report as spam", "timestamp": 1523786005, "user": "moxie"}
Currently what I have that doesn't work
const fs = require('fs');
function convert(input_file_path) {
const file = fs.readFileSync(input_file_path, 'utf8');
const newFormat = file
.replace(/(\r\n\t|\n|\r\t)/gm,'')
.replace(/}{/g, '},{');
console.log([JSON.parse(newFormat)]);
}
convert('myJson.txt');
Since your file contains a JSON object per line, you could read that file line by line, using readline.
Each line is then parsed, and push into an array, which is then returned (resolved) after the file is fully read.
'use strict';
const fs = require('fs');
const readline = require('readline');
function convert(file) {
return new Promise((resolve, reject) => {
const stream = fs.createReadStream(file);
// Handle stream error (IE: file not found)
stream.on('error', reject);
const reader = readline.createInterface({
input: stream
});
const array = [];
reader.on('line', line => {
array.push(JSON.parse(line));
});
reader.on('close', () => resolve(array));
});
}
convert('myJson.txt')
.then(res => {
console.log(res);
})
.catch(err => console.error(err));
I would have done this in this way
var fs = require('fs');
var readline = require('readline');
var array = [];
var input = null;
var rd = readline.createInterface({
input: fs.createReadStream(__dirname+'/demo.txt')
});
rd.on('line', function(line) {
array.push(JSON.parse(line));
});
rd.on('close', function(d){
array.forEach(e=>console.log(e.action))
})
What's happening here is, I am reading the lines of the file on by one using readline which is one of the core modules of nodejs. Listening on the events and doing what needed.
And yeah, you'll have to parse the line to JSON for sure ;)
Thanks
The problem with your code is that you're trying to parse JS array as JSON array. while JSON array string should be only string.
Here what you're trying to do:
jsArray = ['{"foo": "bar"}, {"foo":"baz"}']
This is a valid JS array of a single string value '{"foo": "bar"}, {"foo":"baz"}'.
while
jsonArrayStr = '["{"foo": "bar"}, {"foo":"baz"}"]'
This is a valid JSON array string (as the square brackets is part of the string).
So as to get your code running, you need to add the square brackets to your string before parsing it.
function convert(input_file_path) {
const file = fs.readFileSync(input_file_path, 'utf8');
const newFormat = file
.replace("{", "[{")
.replace(/}$/, "}]")
console.log(JSON.parse('[' + newFormat + ']'));
}
What I'm doing in the script is reading the content of text file line by line and storing it to array along with converting it to JSON object. When we reach last line and our JSON array/object has all the data. Now you can write this object to a new file fs.writeFileSync() after converting JSON object to string with JSON.stringify().
Note :- You've to install Line reader package i.e. npm install line-reader
var lineReader = require('line-reader');
var fs = require('fs')
var jsonObj = {};
var obj = [];
var file = "fileName.json"
var num= 0;
lineRead();
async function lineRead(){
lineReader.eachLine('input.txt', function(line, last) {
// to check on which line we're.
console.log(num);
num++;
convertJson(line)
if(last){
//when it's last line we convert json obj to string and save it to new file.
var data = JSON.stringify(obj)
fs.writeFileSync(file,data);
}
});
}
function convertJson(data){
var currentVal = data
var value = JSON.parse(data)
var temp = value;
//storing the value in json object
jsonObj = value;
obj.push(jsonObj);
}
}
var fs = require("fs");
var text = fs.readFileSync("./mytext.txt").toString('utf-8');
var textByLine = text.split("\n")
while(!text.atEnd())
^ I want to do something like this where it keeps running until the end of the file. Any ideas?
I'm guessing you want to iterate through the returned buffer line by line.
var fs = require("fs");
var text = fs.readFileSync("./mytext.txt").toString('utf-8');
var buffer = text.split("\n")
for (line in buffer) {
// buffer[line] is your current line, do whatever you want with it here
}
There is a cool package I previously used from github for my work. Hope it will work for you also here. See at here https://github.com/nacholibre/node-readlines
var lineByLine = require('n-readlines');
var liner = new lineByLine('./mytext.txt');
var line;
var lineNumber = 0;
while (line = liner.next()) {
console.log('Line ' + lineNumber);
lineNumber++;
}
console.log('end of line reached');
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'm sure making a silly mistake, but can't trace it. Have a simple script to read in a file of the form:
<option value="us">United States</option>
trying to create a new file of the form:
{"value":"us","name":"United States"}
The issue is jsonC.push(c) is not working and the array remains empty. The console.log(c) does print json representation, still the very next line jsonC.push(c) fails to have any effect on jsonC array and it remains empty.
Here is the code:
var fs = require('fs');
var readline = require('readline');
var src = 'country.txt';
var dest = 'country.json';
var re = /.+["](\w{2})["][>]([a-zA-Z ]+)[<][/].+/;
var jsonC = [];
readline.createInterface({
input: fs.createReadStream(src), terminal: false
}).on('line', function(line) {
var match;
if ((match = re.exec(line)) !== null) {
var c = {};
c.value = match[1];
c.name = match[2];
console.log(c); // prints fine
jsonC.push(c); // not adding to the array
}
});
console.log(jsonC); // prints []
console.log(JSON.stringify(jsonC)); // prints []
This is a stand alone node.js v4.2.6 script running on Win 7.
The reason is because you are adding values to jsonC in an callback function. the readline.createInterface(...).on(function() { is a callback, and is not synchronous. So your program is just scheduling that function away, and then it does console.log(jsonC) and jsonC is still empty because the callback hasn't fired yet.
Try outputing the value in the callback, or using promises to know when the callback has finished.
Here is a working example using Promises:
function readFromFile() {
var fsRead = Promise.defer();
readline.createInterface({
input: fs.createReadStream(src), terminal: false
}).on('line', function(line) {
var match;
if ((match = re.exec(line)) !== null) {
var c = {};
c.value = match[1];
c.name = match[2];
jsonC.push(c);
fsRead.resolve();
}
});
return fsRead.promise();
}
readFromFile().then(function(result) {
console.log(jsonC);
})
I'm having a look at JSONStream in node.js, and I'm trying the following small app to get a handle on it:
var JSONStream = require('JSONStream');
var Stream = require('stream');
var s = new Stream();
s.pipe = function(dest) {
dest.write('{"foo":1}');
return dest;
};
var parser = JSONStream.parse(/foo/);
s.pipe(parser).pipe(process.stdout);
Unfortunately, when run on the commandline, this doesn't write anything to the console. What am I doing wrong?
It works if you rewrite your code:
var JSONStream = require('JSONStream');
var Stream = require('stream');
var s = new Stream();
s.pipe = function(dest) {
dest.write('{"foo":1}');
return dest;
};
var parser = JSONStream.parse();
parser.on('data', function(obj) {
console.log('obj', obj);
});
s.pipe(parser);
The reason you can't pipe the output of JSONStream.parse() to process.stdout is that JSONStream outputs objects, and process.stdout only accepts strings (and probably Buffers):
> process.stdout.write({ foo : 1 });
TypeError: invalid data
at WriteStream.Socket.write (net.js:612:11)
...