NodeJS Appending File differently to source file - node.js

So I have some code that takes an input file, Replaces strings in that file and appends those replaced strings to another file.
The problem is that the append function outputs a slightly different file (not where the replaces are). The strings are replaced fine its just some of the lines are swapped and some lines do not have a break.
Code:
const settings = require('../settings.json')
const lineReader = require('line-reader');
const sleep = require('system-sleep')
const Promise = require('bluebird');
var eachLine = Promise.promisify(lineReader.eachLine);
const fs = require('fs')
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
}
return result;
}
fs.stat('./unblacklisted.rbxlx', function(err, stat) {
if(err == null) {
fs.unlink('./unblacklisted.rbxlx', function(err) {
if (err) throw err
})
} else if(err.code === 'ENOENT') {
// file does not exist
} else {
console.log('Some other error: ', err.code);
}
})
eachLine(`./${settings['CorrectMapName/fileName']}`, function(line) {
if (typeof line.split('referent=')[1] !== 'undefined') {
let treatedline = line.replace(/(\r\n|\n|\r)/gm, "");
let test = treatedline.split('referent=')[1]
let hello = (treatedline.replace(test, `"RBX${Buffer.from(makeid(17), 'ascii').toString('hex').toUpperCase()}">`))
fs.appendFile('./unblacklisted.rbxlx',`${hello}\n`, function (err) {
if (err) throw err;
});
} else {
let treatedline = line.replace(/(\r\n|\n|\r)/gm, "");
fs.appendFile('./unblacklisted.rbxlx', `${treatedline}\n`, function (err) {
if (err) throw err;
return;
});
}
}).then(function() {
__callback()
})
The input and output files are XML and I will provide two pastebin URL's for the input file and output file
Input: https://pastebin.com/cHbzL1W6
Output: https://pastebin.com/C53YBwMy
These look very similar but if you run them through a file comparer some lines are switched and vise versa
Would love to fix this, Any help would be GREATLY appreciated

Using jifriend00's first comment I saw that fs.appendFile() was not appending Synchronously
I fixed this by using fs.appendFileSync()
If anyone reading has this problem just use fs.appendFileSync() :D

Related

search keyword from the file and remove line in nodejs

Trying to search a keyword and remove that row from a file. actually it is working fine for me . but I want to show console message if keyword is not found.
from the code lastIndex is the array of search keyword. but how to show a message that the 'keyword not found' if array is empty or undefined!
files.forEach(path => {
var fs = require('fs')
fs.readFile(path, {encoding: 'utf-8'}, function(err, data) {
if (err) {
console.error(err);
return;
}
let dataArray = data.split('\n'); // convert file data in an array
const searchKeyword = 'Searching Word';
let lastIndex = -1; // let say, we have not found the keyword
for (let index=0; index<dataArray.length; index++) {
if (dataArray[index].includes(searchKeyword)) {
lastIndex = index;
var valueAtIndex = dataArray.at(lastIndex);
console.log(valueAtIndex)
break;
}
}
dataArray.splice(lastIndex, 1); // remove the keyword from the data Array
const updatedData = dataArray.join('\n')
fs.writeFile(path, updatedData, (err) => {
if (err) throw err;
console.log ('Successfully updated the file data for : '+path);
})
})
})

How to make while loop with switch case synchrounous in nodejs?

How can I make the while loop with switch-case synchronous in nodejs? Below is the code I am trying to iterate for 2 iterations of the while loop. But the problem is the next iteration gets iterated even before completing all the synchronous functions here which are readdirSync, readFileSync, etc.
What I want is with each whileloop iteration it should run all the methods and then again for next iteration.
Currently the output is:
i = 0
i = 1
Below is my code:
const dir4Data = 'C:/Users/em/Desktop/Regex_test_case/data/google_forms';
const dir4Polls = 'C:/Users/em/Desktop/Regex_test_case/Poll_Report';
var dir, i=0;
var regex4Data = /^\d{1,2}([./-])\d{1,2}\1\d{4}$/;
var regex4Polls = /^[1-9]\d*$/;
while(i < 2)
{
switch (i) {
case 0:
dir = dir4Data;
break;
case 1:
dir = dir4Polls;
break;
}
console.log('i = ', i);
fs.readdirSync(dir, function(err,files){ //Get a listing of all the files in the dir
if (err) throw err;
files.forEach(function(file){
//console.log("file = "+ file);
const writePath = 'C:/Users/em/Desktop/Regex_test_case/output/'+file;
fs.readFileSync(dir+'/'+file, function(err, data) {
console.log("data = "+ data);
var csvContent = data.toString().split('\n'); // read file and convert to array by line break
csvContent.forEach((item, index) => {
var csv;
if(!regex4Data.test(item.toString().split(' ')[0]) && index != 0 && i == 0) {
csv = csvContent[index-1].replace(/(\r\n|\n|\r)/gm, ""); // remove the breaks
// console.log(index, ' Replaced', csv);
fs.appendFileSync(writePath, csvContent[index].toString()+ ' ', function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
else if(!regex4Polls.test(item.toString().split(',')[0]) && index != 0 && i == 1) {
csv = csvContent[index-1].replace(/(\r\n|\n|\r)/gm, ""); // remove the breaks
// console.log(index, ' Replaced', csv);
fs.appendFileSync(writePath, csvContent[index].toString()+ ' ', function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
else {
csv = item.toString();
fs.appendFileSync(writePath, "\n"+csv + " ", function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
});
})
})
})
i++;
}
There are two main error in your script.
First of all, you are using wrong the FS module function.
From the doc, https://nodejs.org/api/fs.html#fs_synchronous_example, all the FS Sync function are synchronous. That means that you don't have to pass them a callback.
You can just write
var response = fs.readFileSync(path);
And the value of response is your file.
The other thing is, if you wont to iterate an async function, you cannot with callback, but you can do it using async/await.
Here an example of loop working:
async function loop() {
var i = 0
while (i < 2) {
var response = await fs.promises.readFile(path);
console.log(response)
i++
}
}

How to get code to execute in order in node.js

I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));

Node.js reading textfiles in current directory and validate

This is actually the answer from my previous question.... the supplied code works for me. All I needed to do was retain a file counter (global) and in the read after validating add to array (global) which gets passed back to rendering process.
// Called from Render Process.
ipcMain.on('search-text-files', (event, arg) => {
const fs = require('fs');
const path = require('path');
var txtArr = [];
var fileName = '';
var fCtr = 0;
fs.readdir(__dirname+'/', function (err, items) {
if (err) {
throw err;
}
// loop through directory items
for (var i=0; i<items.length; i++) {
if (path.extname(items[i].toString() == '.txt') {
fctr+=1;
fileName = items[i].toString();
// read the file & validate
fs.readfile(__dirname+'/'+fileName, (err, data) {
if (err) {
throw err;
}
var checkArr[];
var curFile = '';
checkArr = data.toString().split('\r');
// access contents line by line
for (var line=0; line<checkArr.length; line++) {
... perform some sort of validation
... assign curFile from contents
}
if (file is valid) {
txtArr.push(curfile);
}
fCtr-=1;
if (fCtr == 0) {
event.sender.send('text-files-found', txtArr);
}
});
}
}
});
});

Read the last line of a CSV file and extract one value

New to Node.js and trying to pull a value from the very last line of a CSV file. Here is the CSV:
Unit ID,Date,Time,Audio File
Log File Created,3/6/2013,11:18:25 AM,file:\\\C:\Users\Ben\Documents\1_03-06-2013_1114-50.mp3
1,3/6/2013,11:20:24 AM,file:\\\C:\AlertLog\1_03-06-2013_1120-24.mp3
1,3/6/2013,11:20:39 AM,file:\\\C:\AlertLog\1_03-06-2013_1120-24.mp3
The part I am trying to grab is file:\\\C:\AlertLog\1_03-06-2013_1120-24.mp3 - preferably getting rid of the file:\\\ part.
Sorry that I do not have any code to show, just have a few hours of experience with Node.js and cannot seem to find any docs on how to accomplish something like this. Any help would be appreciated. Thanks!
Regular file
Read the file like a regular file, split the file contents into lines, take the last line, split by a comma and take the last part.
var fs = require('fs'); // file system module
fs.readFile('/path/to/file.csv', 'utf-8', function(err, data) {
if (err) throw err;
var lines = data.trim().split('\n');
var lastLine = lines.slice(-1)[0];
var fields = lastLine.split(',');
var audioFile = fields.slice(-1)[0].replace('file:\\\\', '');
console.log(audioFile);
});
File System module documentation
CSV parser
You can also use the node-csv-parser module.
var fs = require('fs');
var csv = require('csv');
csv()
.from.stream(fs.createReadStream('/path/to/file.csv'))
.to.array(function(data, count) {
var lastLine = data.slice(-1)[0];
var audioFile = lastLine.slice(-1)[0].replace('file:\\\\', '');
console.log(audioFile);
});
I did it by reading the file backwards until the last line was read:
Update 2022 (use modern javascript and read buffer only once)
import { open } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const fileName = path.join(__dirname, 'test.txt');
async function readLastLine(name) {
var line = '';
var chunkSize = 200 // how many characters to read from the end of file
const fd = await open(name);
const st = await fd.stat();
const buf = Buffer.alloc(chunkSize);
const len = buf.length;
const { bytesRead, buffer } = await fd.read(buf, 0, len, st.size - len)
for (let i = len - 1; i > -1; i--) {
const isEol = buffer[i] === 0x0a // 0x0a == '\n'
const isCtrl = buffer[i] < 0x20 // 0-31 are ASCII control characters
if (isEol && line.length > 0) {
break;
} else if (!isCtrl && !isEol) {
line = String.fromCharCode(buffer[i]) + line;
}
}
fd.close();
return line;
}
try {
const line = await readLastLine(fileName)
console.log(line);
} catch (err) {
console.error(err);
}
Old 2014 answer
var fs = require('fs');
var path = require('path');
var fileName = path.join(__dirname, 'test.txt');
var readLastLine = function(name, callback) {
fs.stat(name, function(err, stat) {
fs.open(name, 'r', function(err, fd) {
if(err) throw err;
var i = 0;
var line = '';
var readPrevious = function(buf) {
fs.read(fd, buf, 0, buf.length, stat.size-buf.length-i, function(err, bytesRead, buffer) {
if(err) throw err;
line = String.fromCharCode(buffer[0]) + line;
if (buffer[0] === 0x0a) { //0x0a == '\n'
callback(line);
} else {
i++;
readPrevious(new Buffer(1));
}
});
}
readPrevious(new Buffer(1));
});
});
}
readLastLine(fileName, function(line) {
console.log(line);
});

Resources