Creating text files from array, using FS - javascript

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,''));

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}.`);
});

nodejs fs createWriteStream not working with file path prefix

I am trying to call an API, loop through an array of images, assign unique names to each image in the array and then write them to a local directory. If I simplify the code I can write them to the root folder .I already created the sub folder manually, so it existed prior to running the function.
Here is my basic function:
const imageFolder = './img';
function downloadImage(url, filepath) {
client.get(url, res => {
res.pipe(fs.createWriteStream(`${imageFolder}/${filepath}`));
});
}
...make api call
const imagesArray = generations.data.map(item => item.generation.image_path);
imagesArray.forEach(item => {
// const fileName = uuid.v4() + '.webp'; // trying to assign unique filename with uuid
const fileName = new Date().getTime().toString() + '.webp'; // trying to assign unique filename with date object
downloadImage(item, fileName);
});
If I change
res.pipe(fs.createWriteStream(`${imageFolder}/${filepath}`));
to
res.pipe(fs.createWriteStream(filepath));
then it will work but just dumps the images in the root. I was thinking perhaps I was trying to concatenate a variable name with a string (for fileName + '.webp', but it is working in the root as mentioned. See attached image.
I also tried adding the path into the actual function call inside the forEach loop like so
downloadImage(item, `${imageFolder}/${fileName}`);
I did wonder about needing the __dirname variable, or whether it could be a permissions issue, but I don't see any errors.
I am assuming this is pretty straightforward.
OK, was fairly simple and I guess I sort of knew it once I got it working, changing to
downloadImage(item, path.join('src', 'img', fileName));
path.join concatenates folder names and fixes issues when working across platforms (OSX, Windows etc) which applies in this case as I am testing from both Windows and Mac.

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

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

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.

Can't parse JSON file - Unexpected token

I've created json file using Visual studio:
{
"test": "asd"
}
Using this code to read it:
var test = fs.readFileSync('./files/test.json')
var obj = JSON.parse(test);
which results in error: Unexpected token  in JSON at position 0
When I try to read package.json, it is read correctly. Does anyone know why I can't read my file?
You have 2 options
add encoding option
var test = fs.readFileSync('./files/test.json', {encoding: 'utf8'})
var obj = JSON.parse(test);
If the encoding option is specified then this function returns a string. Otherwise it returns a buffer.
require json
var obj = require('./files/test.json');
As of node v0.5.x yes you can require your JSON just as you would require a js file.
I hope this code help u
$.getJSON("/files/test.json", function(json) {
alert(json['test'])
//if massage show 'object object' then firs purse
//json=JSON.parse(json) //alert(json['test']) });
Solution of the problem is opening file in notepad++ and saving it without BOM. Looks like json created via visual studio adds BOM
It looks like this is not properly formatted JSON. They modifying it like this.
var myObject = {
'test': 'asd'
};
and then you parse would be....
var obj = JSON.parse(myObject);

Categories