Caveat: I am posting this as the accepted answer doesn't work. However I am no expert on Windows file locking but this is what I have been able to cobble together:
On Windows there seem to be 3 types of lock which cause the EBUSY
in Node.
- Files locked with an 'exclusive lock'
- Executable files locked by the OS which are currently running
- e.g. when you run a
setup.exe
- System protected files
Option A:
Node fs is built on libuv which allows passing advanced options to request an exclusive lock. This seems
to be the safest technique as there is no chance of changing/corrupting the file.
Open the file with UV_FS_O_RDONLY and UV_FS_O_EXLOCK
EBUSY returned for 1, 2 and 3.
try {
const fileHandle = await fs.promises.open(filePath, fs.constants.O_RDONLY | 0x10000000);
fileHandle.close();
} catch (error) {
if (error.code === 'EBUSY'){
console.log('file is busy');
} else {
throw error;
}
}
Note: this requires libuv >= 1.17.0
, which is satisfied by NodeJS >= 8.10.0
Option B:
Performing an fs.rename()
also reliably fails on a locked file, doesn't require any OS specific flags, but is more dangerous as you could introduce race condition bugs as the file is actually moved temporarily.
EBUSY returned for 1, 2 and 3.
try {
await fs.promises.rename(filePath, filePathNew);
await fs.promises.rename(filePathNew, filePath);
} catch (error) {
if (error.code === 'EBUSY'){
console.log('file is busy');
} else {
throw error;
}
}
Option C (do not use):
Perform an fs.open(..., 'r+')
. This DOES NOT WORK for files with an exclusive lock 1, no error is returned.
EBUSY returned for 2 and 3.
try {
await fs.promises.open(filePath, 'r+');
} catch (error) {
if (error.code === 'EBUSY'){
console.log('file is busy');
} else {
throw error;
}
}