I would like to create a file foobar. However, if the user already has a file named foobar then I don't want to overwrite theirs. So I only want to create foobar if it doesn't exist already.
At first, I thought that I should do this:
fs.exists(filename, function(exists) {
if(exists) {
// Create file
}
else {
console.log("Refusing to overwrite existing", filename);
}
});
However, looking at the official documentation for fs.exists, it reads:
fs.exists() is an anachronism and exists only for historical reasons.
There should almost never be a reason to use it in your own code.
In particular, checking if a file exists before opening it is an
anti-pattern that leaves you vulnerable to race conditions: another
process may remove the file between the calls to fs.exists() and
fs.open(). Just open the file and handle the error when it's not
there.
fs.exists() will be deprecated.
Clearly the node developers think my method is a bad idea. Also, I don't want to use a function that will be deprecated.
How can I create a file without writing over an existing one?
I think the answer is:
Just open the file and handle the error when it's not there.
Try something like:
function createFile(filename) {
fs.open(filename,'r',function(err, fd){
if (err) {
fs.writeFile(filename, '', function(err) {
if(err) {
console.log(err);
}
console.log("The file was saved!");
});
} else {
console.log("The file exists!");
}
});
}
fs.closeSync(fs.openSync('/var/log/my.log', 'a'))
import { promises as fs } from "fs";
fs.readFile(path).catch(() =>
fs.writeFile(path, content);
);
If you would like to write data to this file later, you can use fs.appendFile('message.txt', 'data to append', 'utf8', callback);.
Asynchronously append data to a file, creating the file if it does not yet exist. Data can be a string or a buffer.
Node file system documentation.
Related
Often I need to check if a dependency exists in webpack. For example, I have a bunch of ids like [0,1,3,4,5,6,7,8,...] and some of them have an image I should load while others don't.
How I check that an image should be loaded is by creating an array that contains the values that have an image and just do an array.contains when checking that the image should be loaded. Like [1,5,7,...].
This is starting to be quite problematic because I need to change this array every time I add or remove images.
Is there a way to check if the module I want to require exists or not?
As far as I see there was a way in Webpack 1 but that go closed.
https://github.com/webpack/webpack/issues/526
I found that it should still work like this according to the documentation (https://webpack.js.org/api/module-methods/#require-resolveweak) but I do get Error: Cannot find module.
This is what I'm doing exactly:
$scope.getExplorationImage = function (imageId) {
if(__webpack_modules__[require.resolveWeak('image/exploration/' + imageId + '.png')]) {
console.log("Image exists for: "+imageId)
return require('image/exploration/' + imageId + '.png');
} else {
console.log("Image doesn't exists: "+imageId)
}
};
I'm using Webpack 3.5.5. I want to avoid the try/catch solution if possible.
I know the question states
I want to avoid the try/catch solution if possible.
However, if someone comes by here trying to get webpack not to crash while testing if module exists, here is what works:
// try if module exists
try {
var module = require('../path/to/module');
}
// fallback if does not exists
catch(err) {
var module = require('../path/to/fallback/module');
}
You will still get an error printed in the console, but webpack won't crash the application and correctly fallback to module provided in the catch{};
what you did is the way but it only checks if that module was already loaded, you need to turn it into an async function if you want to check if that module is available.
have a look here: https://github.com/webpack/webpack/issues/526
you can write a function to simplyfy everything:
function moduleExists(moduleId) {
return new Promise((resolve, reject) => {
// check if that module was already loaded
if(__webpack_modules__[require.resolveWeak(moduleId)]) {
return resolve();
}
return import(moduleId)
.then(() => resolve(), () => reject())
;
});
}
moduleExists('foobaz' /* take care of absolute paths */ )
.then(() => alert('yes'))
.catch(() => alert('noope'))
;
const exists = await moduleExists('bar');
if(exists) { /* do stuff */ }
import(/* webpackIgnore: true */ 'ignored-module.js');
https://webpack.js.org/api/module-methods/#magic-comments
I'm pretty new to node.js and it seems fairly easy to use but when it comes to getting a value using the command line and returning that value to be used in another package or .js, it seems harder than I expected.
Long story short, I've used a npm package (akamai-ccu-purge), to enter a file to purge on the akamai network successfully.
I want to make it more dynamic though by prompting the user to enter the file they want purged and then using that in the akamai package.
After making a few tries using var stdin = process.openStdin(); I actually found another npm package called Prompt that seemed to be easier. Both ways seem to have the same problem though.
Node doesn't seem to want to stop for the input. It seems to want to automatically make the purge without waiting for input even though I've called that module first. It actually gets to the point where I should enter the file but it doesn't wait.
I am definitely missing something in my understanding or usage here, what am I doing wrong?
My code so far is:
var purgeUrl = require('./getUrl2');
var PurgerFactory = require('../../node_modules/akamai-ccu-purge/index'); // this is the directory where the index.js of the node module was installed
// area where I placed the authentication tokens
var config = {
clientToken: //my tokens and secrets akamai requires
};
// area where urls are placed. More than one can be listed with comma separated values
var objects = [
purgeUrl // I am trying to pull this from the getUrl2 module
];
// Go for it!
var Purger = PurgerFactory.create(config);
Purger.purgeObjects(objects, function(err, res) {
console.log('------------------------');
console.log('Purge Result:', res.body);
console.log('------------------------');
Purger.checkPurgeStatus(res.body.progressUri, function(err, res) {
console.log('Purge Status', res.body);
console.log('------------------------');
Purger.checkQueueLength(function(err, res) {
console.log('Queue Length', res.body);
console.log('------------------------');
});
});
});
The getUrl2 module looks like this:
var prompt = require('../../node_modules/prompt');
//
// Start the prompt
//
prompt.start();
//
// Get property from the user
//
prompt.get(['newUrl'], function (err, result) {
//
// Log the results.
//
console.log('Command-line input received:');
console.log(' http://example.com/custom/' + result.newUrl);
var purgeUrl = 'http://example.com/custom/' + result.newUrl;
console.log(purgeUrl);
module.exports = purgeUrl;
});
Thanks again for the help!
I would probably just allow getURL2 to expose a method that will be invoked in the main module. For example:
// getURL2
var prompt = require('../../node_modules/prompt');
module.exports = {
start: function(callback) {
prompt.start();
prompt.get(['newUrl'], function (err, result) {
// the callback is defined in your main module
return callback('http://example.com/custom/' + result.newUrl);
});
}
}
Then in your main module:
require('./getUrl2').start(function(purgeURL) {
// do stuff with the purgeURL defined in the other module
});
The implementation may differ, but conceptually, you need to make your second module, which requires some sort of input from the user, happen as a result of that input. Callbacks are a common way to do this (as are Promises). However, as prompt is not necessarily exposing a method that would necessitate a Promise, you can do it with plain old callbacks.
You might also want to search around for articles on writing command line tools (sometimes referenced as CLIs) or command line apps with Node. I found the following article to be helpful when trying to figure this out myself:
http://javascriptplayground.com/blog/2015/03/node-command-line-tool/
Also, the command-line-args module worked well for me (though there's a number of other modules out there to choose from):
https://www.npmjs.com/package/command-line-args
Good luck!
I'm not sure how to use the tmp package of node correctly. Maybe someone can give me an example
Filename generation
It is possible with this library to generate a unique filename in the
specified directory.
var tmp = require('tmp');
tmp.tmpName(function _tempNameGenerated(err, path) {
if (err) throw err;
console.log("Created temporary filename: ", path);
});
But what and how do I pass path. As I understand it, it makes sure, that in my desired directory are just unique filenames. So do I have to pass my for example upload directory as path? (But how syntax wise?)
Documentation
You don't.
You call tmpName, it calls its callback with an error (err, null if there isn't one) and the path.
Inside the callback you do what you want to do with the temporary filename, like write something to it.
Just started coding last thursday, bear with me here:
my code for this question of the tutorial is returning a list of just the extension names from the directory and not a list of the files with the said extension, e.g. if i used a directory with 3 .js files and used js as my extension argument in the command line, then i would get
1. js
2. js
3. js
as the output, here is the question from the tutorial and my code. THANK YOU!
the question from learnyounode tutorial number 6:
LEARN YOU THE NODE.JS FOR MUCH WIN!
─────────────────────────────────────
MAKE IT MODULAR
Exercise 6 of 13
This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this.
Create a program that prints a list of files in a given directory, filtered by the extension of the files. The first argument is the directory name and the second argument is the extension filter. Pr
int the list of files (one file per line) to the console. You must use asynchronous I/O.
You must write a module file to do most of the work. The module must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in
that order. The filename extension argument must be the same as was passed to your program. i.e. don't turn it into a RegExp or prefix with "." or do anything else but pass it to your module where y
ou can do what you need to make your filter work.
The callback function must be called using the idiomatic node(err, data) convention. This convention stipulates that unless there's an error, the first argument passed to the callback will be null, a
nd the second will be your data. In this case, the data will be your filtered list of files, as an Array. If you receive an error, e.g. from your call to fs.readdir(), the callback must be called wi
th the error, and only the error, as the first argument.
You must not print directly to the console from your module file, only from your original program.
In the case of an error bubbling up to your original program file, simply check for it and print an informative message to the console.
These four things are the contract that your module must follow.
Export a single function that takes exactly the arguments described.
Call the callback exactly once with an error or some data as described.
Don't change anything else, like global variables or stdout.
Handle all the errors that may occur and pass them to the callback.
The benefit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work. *
and my code is:
module (p6m.js):
var fs=require('fs'), ph=require('path'), exports =module.exports={}
exports.f=function(path,ext,callbk){
fs.readdir(path,function(err,files){
if(err){
return callbk(err,null)
}
files=files.filter(
function(file){
return ph.extname(file)==="."+ext
}
)
return callbk(null,files)}
)}
and my program (p6.js):
var p6m=require('./p6m'), path=process.argv[2], ext=process.argv[3]
p6m.f(path, ext, function(err,files){
if(err){return console.log.error('Error occured:', err)};
files.forEach(function(file){
console.log(file)})})
I got the same problem with my code as of need to use a single function export . So instead of exporting a module function like this :
exports =module.exports={}
exports.f=function(path,ext,callbk){...};
try it doing this way :
module.exports = function (path, ext, callbk) {...};
because its a single function so you don't need to specify that function with a name " f " as if you are doing it in this statement :
exports.f = function(path,ext,callbk){...};
whenever you will import the module,it will automatically call this function only, since the module contains this single function.
You can try this piece of code, it works well for me.
module code: mymodule.js
var fs = require('fs');
var ph= require('path');
module.exports = function (path, ext, callbk) {
var pathio = "." + ext;
fs.readdir(path, function (err, files) {
if (err)
return callbk(err);
else {
var listf = []; //listf is the resultant list
for (var i = 0; i < files.length; i++) {
if (ph.extname(files[i]) === pathio) {
listf.push(files[i]);
}
}
callbk(null, listf);
}
});
}
program code : moduletest.js
var mod = require('./mymodule');
mod(process.argv[2], process.argv[3], function (err, listf) {
if (err) {
console.log('Error!')
} else {
for (var i = 0; i < listf.length; i++) {
console.log(listf[i]);
}
}
});
and do remember, learnyounode series is very specific about its way of coding and syntax, so even if you are doing the logic right way still you won't get pass,you need your code to be the best and optimized. I'll suggest you to refer to discussions on nodeschool itself for various issues you might get in learnyounode series.
That will work and output the right results, but what they are looking for is something like this:
module.exports = function() {};
Because they only want one function total in the exports.
You could also do something like this:
module.exports = FindFilesByExtension;
function FindFilesByExtension(path, ext, callback) {
//your code
}
Here is my solution,
Thsi is my module file filteredls.js
var fs = require('fs');
var path = require('path');
module.exports = function filterFiles(folder, extension, callback) {
fs.readdir(folder, function(err, files) {
if(err) return callback(err);
var filesArray = [];
files.forEach(function(file) {
if(path.extname(file) === "."+extension) {
filesArray.push(file);
}
});
return callback(null, filesArray);
});
}
And here is my test file for reading module modular.js
var ff = require('./filteredls.js');
ff(process.argv[2], process.argv[3], function(err, data) {
if(err)
return console.error(err);
data.forEach(function(file) {
console.log(file);
});
});
And this is my result screenshot,
I'm trying to call fs.exists in a node script but I get the error:
TypeError: Object # has no method 'exists'
I've tried replacing fs.exists() with require('fs').exists and even require('path').exists (just in case), but neither of these even list the method exists() with my IDE. fs is declared at the top of my script as fs = require('fs'); and I've used it previously to read files.
How can I call exists()?
Your require statement may be incorrect, make sure you have the following
var fs = require("fs");
fs.exists("/path/to/file",function(exists){
// handle result
});
Read the documentation here
http://nodejs.org/api/fs.html#fs_fs_exists_path_callback
You should be using fs.stats or fs.access instead. From the node documentation, exists is deprecated (possibly removed.)
If you are trying to do more than check existence, the documentation says to use fs.open. To example
fs.access('myfile', (err) => {
if (!err) {
console.log('myfile exists');
return;
}
console.log('myfile does not exist');
});
Do NOT use fs.exists please read its API doc for alternative
this is the suggested alternative : go ahead and open file then handle error if any :
var fs = require('fs');
var cb_done_open_file = function(interesting_file, fd) {
console.log("Done opening file : " + interesting_file);
// we know the file exists and is readable
// now do something interesting with given file handle
};
// ------------ open file -------------------- //
// var interesting_file = "/tmp/aaa"; // does not exist
var interesting_file = "/some/cool_file";
var open_flags = "r";
fs.open(interesting_file, open_flags, function(error, fd) {
if (error) {
// either file does not exist or simply is not readable
throw new Error("ERROR - failed to open file : " + interesting_file);
}
cb_done_open_file(interesting_file, fd);
});
As others have pointed out, fs.exists is deprecated, in part because it uses a single (success: boolean) parameter instead of the much more common (error, result) parameters present nearly everywhere else.
However, fs.existsSync is not deprecated (because it doesn't use a callback, it just returns a value), and if the whole rest of your script depends on checking the existence of a single file, it can make things easier than having to deal with callbacks or surrounding the call with try/catch (in the case of accessSync):
const fs = require('fs');
if (fs.existsSync(path)) {
// It exists
} else {
// It doesn't exist
}
Of course, existsSync is synchronous and blocking. While this can sometimes be handy, if you need to do other operations in parallel (such as checking for the existence of multiple files at once), you should use one one of the other callback-based methods.
Modern versions of Node also support promise-based versions of fs methods, which one might prefer over callbacks:
fs.promises.access(path)
.then(() => {
// It exists
})
.catch(() => {
// It doesn't exist
});