JavaScript - reading JSON file with require gives different result than fs.readFileSync - javascript

I'm getting an issue that makes me think there's something I'm missing about how require works in JavaScript. Basically, if I use require to read a JSON file, I get a different result than using fs.readFileSync.
I start with a JSON file with the following contents:
{"text":"old text"}
I first read the file with require and fs.readFileSync and get the same results for each. I then update the file with fs.writeFileSync and read the file again with require and fs.readFileSync, but I get different results after updating.
It's important to note that I'm requiring the file from inside a function. I would expect this to import the file separately with each function call, but that's apparently not what's happening. Just wondering if someone can explain exactly what's happening.
const fs = require('fs');
const textPath = './test.json';
const oldTextJSON = getText(); // prints as "old text"
const oldTextRead = JSON.parse(fs.readFileSync(textPath)).text; // prints as "old text"
fs.writeFileSync(textPath, JSON.stringify({
text: "new text"
}));
const newTextJson = getText(); // prints as "old text"
const newTextRead = JSON.parse(fs.readFileSync(textPath)).text; // prints as "new text"
function getText() {
return require(textPath).text;
}

Hope this one line explain the characteristics of require.
const path = require("path");
const filepath = path.resolve(textPath);
delete require.cache[filepath];
Basically require reads from the cache no matter how many times you call.

Related

Questions about fs.writeFile

I want to use fs.WriteFile in my JS project. I am building an algorithm that outputs random data and I want to give the user the opportunity to save the data as a txt file. I have been able to implement fs.WriteFile in my project, but I have a couple of questions on how to proceed next as the function remains somewhat unclear.
How do I specify that I want to include the contents of various vars? Is it as simple as data = let1 + let2 + let3 and all of the data will be included?
can I add the current date and time in the .txt file name? If so, how?
How do I tell writeFile to save the contents to a .txt file and open a download blob so that people can specify their own download locations?
Thanks in advance!
I've tried looking at basic documentation but its mainly the same: a template using a simple string that saves into the same directory, which is what I don't want.
For you first question, you are correct. You can just combine different string variables into a larger string variable. See the documentation for string concatenation for more information.
For your second question, yes you can. You can get the current date and time with new Date() and turn it into a variety of formats. For file names, using mydate.toISOString() will probably be the most clean.
Here's an example of both of these in practice:
import fs from 'fs';
// Here's some data that we want to put in the file.
const name = "Bob";
const age = 43;
// Create the data we want to put in our file.
const data = name + '\n' + age;
// Let's grab the date and use it as part of our file name.
const date = new Date();
const fileName = `${date.toISOString()}.txt`;
// Call fs.writeFile to put the data in the file.
fs.writeFile(fileName, data, () => {
console.log(`Wrote data to ${fileName}.`);
});
Your third question is more complicated and probably worth a separate post. fs.writeFile can't do this for you. You'll have to come up with some mechanism for the user to enter their own file name and build off of that.
Edit:
To address your question in the comments, you might be a little confused with how NodeJS works. NodeJS runs on the server and doesn't have any way to deal with buttons or UIs by default like browser JavaScript does. It might be helpful to look at the differences between the two. So you won't be able to save it to the downloads folder on a button click.
With that said, we can save the file to the user's Downloads folder with the same script I posted above by adding the path to the Downloads folder to the beginning of the file name.
Here's the code above adjusted to do that:
import fs from 'fs';
import os from 'os'; // NEW
import path from 'path'; // NEW
const name = "Bob";
const age = 43;
const data = name + '\n' + age;
const date = new Date();
const fileName = `${date.toISOString()}.txt`;
// Get the user's home directory.
const homedir = os.homedir();
// Append the Downloads directory and fileName to the user's home directory.
const fullPath = path.join(homedir, 'Downloads', fileName);
// Use fullPath here instead of fileName.
fs.writeFile(fullPath, data, () => {
console.log(`Wrote data to ${fileName}.`);
});

Unexpected end of JSON input at parse (<anonymous>)

I'm tring to write to an exist JSON and i've noticed that I should read the file insert the new item and then writing again , its working on most times but sometimes I recieve this error " Unexpected end of JSON input at parse ()" , and hole data in json are deleted .
app.post(APIClonePath,(req,res)=>{
const body = req.body
let cloneTicket:Ticket = body.ticket
let ticketID = body.id
let fs = require('fs')
// #ts-ignore
fs.readFile('./data.json',(err,data) =>{
if(err){
throw new Error('ERROR in reading JSON')
// res.send(false)
}
let ticketsInJSON = JSON.parse(data)
let indexOfOriginTicket
for(let index = 0; index < ticketsInJSON.length ; index++){
if(ticketsInJSON[index].id.valueOf() === ticketID){
indexOfOriginTicket = index
break
}
}
// #ts-ignore
ticketsInJSON.splice(indexOfOriginTicket,0,cloneTicket)
let writingArray = JSON.stringify(ticketsInJSON)
writeFile('./data.json',writingArray,function (){})
})
res.send(true)
})
1st. mode fs declaration to the file header with all other requires.
2nd. you use // #ts-ignore as this would be TS file, and you are using require instead of import.
3rd. you answer user TRUE before you even read the file, you also dont have any precaution against many file access in this code. Imagine more than one ppl are executing your code, one read the file, the the same guy starts writing to the file, while other guy just started reading the not saved file - you never know what can happen.
4th. you ignore anything from writeFile function which can tell you information about errors while writing file.
5th. if you do not find index, you try to splice with undefined instead of index - that also can make problems

How to automatically pass on all the picture file paths to an array?

I need to add a bunch of playing cards jpg paths into an array, so that I can assign them later as src="" of
Alternatively add the jpg paths to an object
I'm working with javascript, I'm not too sure if it should be a syncronous or async function.
i got this from some other stackoverflow question, but i don't understand it and it doesn't work. I don't understand the fs stuff.
const fs = require('fs');
fs.readdirSync("pics").forEach(file => {
console.log(file);
});
fs.readdirSync("pics") already returns an array.
Your code should be:
const pathArray = fs.readdirSync("pics");
As long as "pics" is the path of the folder you want to read from.

Creating text files from array, using FS

I created an array of strings and placed them into an array called schoolsArray. I want to be able to create a text file for each school, using fs.
For some reason, I just can't get this to work. It seems that the issue is with using the value from schoolsArray[0] as a string in the path name. Please take a look at my series of tests. This first code snippet all works, but I added it just to help you understand that I import 'fs' and create a directory first.
Update - Added schoolArray creation per request
var fs = require('fs');
// Read all schools into array (read from text file)
const schoolFile = "./assets/dispatch/state/schools/county_name.txt";
fileInput = fs.readFileSync(schoolFile, "utf-8");
const schoolArray = fileInput.split("\n");
// Variable for chat logs directory
const chatDir = "./chat-logs";
// Create directory if it doesn't exist
if(!fs.existsSync(chatDir)){
fs.mkdirSync(chatDir);
}
The directory is created, now try make a file attempt #1
var schoolTextFile = chatDir + "/" + schoolArray[0] + ".txt";
fs.writeFileSync(schoolTextFile, "");
Uncaught Error: ENOENT: no such file or directory, open 'C:\Users\PC\Desktop\Node_Webkit_Test\chat-logs\Test School Name.txt'
at Object.fs.openSync (fs.js:653:18)
at Object.fs.writeFileSync (fs.js:1300:33)
Okay, so that doesn't work for some reason. Attempt #2 - I have come to think that the schoolArray[0] value isn't being read as a string, so I tried this:
var schoolTextFile = chatDir + "/" + toString(schoolArray[0]) + ".txt";
fs.writeFileSync(schoolTextFile, "");
There are no errors here, but the output is an undefined object:
Attempt #3 was to simply try a text string instead of using the value from my array. This worked exactly as intended.
var schoolTextFile = chatDir + "/" + "some Text 1234" + ".txt";
fs.writeFileSync(schoolTextFile, "");
Thus, the issue is pinpointed to be with the schoolArray[0] value being entered into the path. It seems silly to even test, but I did this anyway...
var somestring = "some text 1234";
console.log(typeof somestring);
// The log says that this is a string.
console.log(typeof schoolArray[0]);
// The log says that this is a string.
So then, why does one string work here, and the other causes path issues? Thanks in advance!
You must have some forbidden characters in schoolArray. Typically \r. Try
schoolArray = fileInput.split("\n").map( line => line.replace(/\r/g,''));

How do you read a file or Stream synchronously in node.js?

Please, no lectures about how I should be doing everything asynchronously. Sometimes I want to do things the easy obvious way, so I can move on to other work.
For some reason, the following code doesn't work. It matches code I found on a recent SO question. Did node change or break something?
var fs = require('fs');
var rs = fs.createReadStream('myfilename'); // for example
// but I might also want to read from
// stdio, an HTTP request, etc...
var buffer = rs.read(); // simple for SCCCE example, normally you'd repeat in a loop...
console.log(buffer.toString());
After the read, the buffer is null.
Looking at rs in the debugger, I see
events
has end and open functions, nothing else
_readableState
buffer = Array[0]
emittedReadable = false
flowing = false <<< this appears to be correct
lots of other false/nulls/undefined
fd = null <<< suspicious???
readable = true
lots of other false/nulls/undefined
To read the contents of a file synchronously use fs.readFileSync
var fs = require('fs');
var content = fs.readFileSync('myfilename');
console.log(content);
fs.createReadStream creates a ReadStream.

Categories