Hamza
Hamza

Reputation: 131

Using fs.stat and fs.writeFile

I need to check for the existence of a file before executing fs.writeFile, so if the file already exists, fs.writeFile sould not replace the file. But the documentation says the following :

Using fs.stat() to check for the existence of a file before calling fs.open(), fs.readFile() or fs.writeFile() is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available.

If I call fs.writeFile directly, the function will replace the file if it already exists, and the error variable will be null.

I want to ignore the call to fs.writeFile if the file already exists.

Thanks.

Upvotes: 0

Views: 1039

Answers (2)

jfriend00
jfriend00

Reputation: 707446

Robert has the correct answer (just pass in the appropriate flags fs.writeFile(fname, data, { flag : 'wx' }, ...)), but I thought I would explain why it is not recommended to use fs.stat() followed by fs.writeFile(). When you do something like this:

fs.stat(fname, function(err) {
    if (err) {
       // in the bit of time right here, there is a race condition
       fs.writeFile(fname, data, function(err) {
           // file written
       });
    }
});

There is a race condition. In any sort of multi-process system or any sort of file system shared with other systems, there can be a situation where fs.stat() reports the file is not there, but between that moment and the time that you actually call fs.writeFile(), some other process or thread or computer writes that file and now you've just overwritten an existing file which is something you did not want to do. So, this is simply not reliable in some circumstances and thus is not recommended.

What you need instead is an atomic operation that will both check if it's there and, if not, will create it for you. That will give you a reliable system so that the file will never be accidentally overwritten.

By passing the wx flags to fs.writeFile(), you tell the underlying OS to write these bytes to the file only if the file doesn't already exist and it will be done in an atomic fashion that does not have multi-thread/process/computer race conditions.


There are limits to the race condition and there are situations where your system would not actually be subject to it (only one node.js process that can ever write to that file), but it is simply safer to just always code in the safe way, no matter what and, in fact, the safe way is less code too.

Upvotes: 2

robertklep
robertklep

Reputation: 203359

I want to ignore the call to fs.writeFile if the file already exists.

Use the wx flag (documented here):

wx - Like 'w' but fails if path exists.

fs.writeFile('/path/to/file', data, { flag : 'wx' }, function(err) {
  if (err && err.code === 'EEXIST') {
    console.log('file already exists, not overwriting');
    return;
  }
  ...
})

EDIT: the reason it's not recommended to use fs.stat before fs.open/fs.writeFile/fs.readFile is because of an inherent race condition: in between the calls to fs.stat and (say) fs.writeFile, there's a small window of time in which a file could get created, even though it didn't yet exist when fs.stat was called. So there would still be a chance that fs.writeFile could overwrite an existing file.

If you use file flags, the check for existence is done atomically.

Upvotes: 2

Related Questions