24

I'm generating files automatically, and I have another script which will check if a given file is already generated, so how could I implement such a function:

function checkExistsWithTimeout(path, timeout)

which will check if a path exists, if not, wait for it, util timeout.

Soviut
  • 88,194
  • 49
  • 192
  • 260
wong2
  • 34,358
  • 48
  • 134
  • 179

8 Answers8

22

Assuming you're planning on using Promises since you did not supply a callback in your method signature, you could check if the file exists and watch the directory at the same time, then resolve if the file exists, or the file is created before the timeout occurs.

function checkExistsWithTimeout(filePath, timeout) {
    return new Promise(function (resolve, reject) {

        var timer = setTimeout(function () {
            watcher.close();
            reject(new Error('File did not exists and was not created during the timeout.'));
        }, timeout);

        fs.access(filePath, fs.constants.R_OK, function (err) {
            if (!err) {
                clearTimeout(timer);
                watcher.close();
                resolve();
            }
        });

        var dir = path.dirname(filePath);
        var basename = path.basename(filePath);
        var watcher = fs.watch(dir, function (eventType, filename) {
            if (eventType === 'rename' && filename === basename) {
                clearTimeout(timer);
                watcher.close();
                resolve();
            }
        });
    });
}
Jake Holzinger
  • 5,783
  • 2
  • 19
  • 33
7

fs.watch() API is what you need.

Be sure to read all the caveats mentioned there before you use it.

Aftab Khan
  • 3,853
  • 1
  • 21
  • 30
  • 8
    I don't find this so useful as fs.watch seems to need the file to exist before it can be watched ... – Sam Joseph Sep 06 '17 at 16:44
  • 7
    @SamJoseph you can watch the parent directory and wait for an event that will say that the file you are waiting for has just arrived. – Anthony O. Sep 12 '18 at 19:26
3
import fs from 'node:fs'; //es6
//or
const fs = require('fs'); //commonjs


/**
*
* @param {String} filePath
* @param {Number} timeout
* @returns {Promise<Boolean>}
*/
const holdBeforeFileExists = async (filePath, timeout) => {
  timeout = timeout < 1000 ? 1000 : timeout
  try {
    var nom = 0
      return new Promise(resolve => {
        var inter = setInterval(() => {
          nom = nom + 100
          if (nom >= timeout) {
            clearInterval(inter)
            //maybe exists, but my time is up! 
            resolve(false)
          }

          if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
            clearInterval(inter)
            //clear timer, even though there's still plenty of time left
            resolve(true)
          }
        }, 100)
      })
  } catch (error) {
    return false
  }
}

(async()=>{
  const maxTimeToCheck = 3000; //3 second
  const fileCreated = '/path/filename.ext';
  const isFile = await holdBeforeFileExists(fileCreated, maxTimeToCheck);
  //Result boolean true | false
})();

It's work goodssssssssssss................!!!
Try it before giving bad comments.
Enjoy your Kopi mana kopi obat kagak ngantuk???

express js:

router.get('some_url', async(req, res)=>{
    const fileCreated = someFunctionCreateFileWithResultStringPathName();
    const maxTimeToCheck = 3000; //3 second
    const isFile = await holdBeforeFileExists(fileCreated, maxTimeToCheck);
    if(isFile){
        res.sendFile(fileCreated)
    } else {
        res.send('Failed to generate file, because use a bad function to generate file. or too long to create a file');
    }
})
  • setTimeout should reject, or resolve with false boolean, now it's always passing, no matter if file exists or not – MushyPeas Mar 18 '22 at 11:26
2

Here is the solution:

// Wait for file to exist, checks every 2 seconds by default
function getFile(path, timeout=2000) {
    const intervalObj = setInterval(function() {

        const file = path;
        const fileExists = fs.existsSync(file);

        console.log('Checking for: ', file);
        console.log('Exists: ', fileExists);

        if (fileExists) {
            clearInterval(intervalObj);
        }
    }, timeout);
};
Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
TetraDev
  • 16,074
  • 6
  • 60
  • 61
1

You could implement it like this if you have node 6 or higher.

const fs = require('fs')

function checkExistsWithTimeout(path, timeout) {
  return new Promise((resolve, reject) => {
    const timeoutTimerId = setTimeout(handleTimeout, timeout)
    const interval = timeout / 6
    let intervalTimerId

    function handleTimeout() {
      clearTimeout(timerId)

      const error = new Error('path check timed out')
      error.name = 'PATH_CHECK_TIMED_OUT'
      reject(error)
    }

    function handleInterval() {
      fs.access(path, (err) => {
        if(err) {
          intervalTimerId = setTimeout(handleInterval, interval)
        } else {
          clearTimeout(timeoutTimerId)
          resolve(path)
        }
      })
    }

    intervalTimerId = setTimeout(handleInterval, interval)
  })
}
Siggy
  • 324
  • 2
  • 11
1

Here another version that works for me :

async function checkFileExist(path, timeout = 2000)
{
    let totalTime = 0; 
    let checkTime = timeout / 10;

    return await new Promise((resolve, reject) => {
        const timer = setInterval(function() {

            totalTime += checkTime;
    
            let fileExists = fs.existsSync(path);
    
            if (fileExists || totalTime >= timeout) {
                clearInterval(timer);
                
                resolve(fileExists);
                
            }
        }, checkTime);
    });

}

You can simply use it :

await checkFileExist("c:/tmp/myfile.png");
kamel B
  • 303
  • 1
  • 3
  • 9
-1
function verifyFileDownload(extension) {
    browser.sleep(150000); //waiting for file to download
    const fs = require('fs');
    let os = require('os');
    var flag = true;
    console.log(os.userInfo());
    fs.readdir('/Users/' + require("os").userInfo().username + '/Downloads/', (error, file) => {
        if (error) {
            throw error;
        }
        console.log('File name' + file);
        for (var i = 0; i < file.length; i++) {
            const fileParts = file[i].split('.');
            const ext = fileParts[fileParts.length - 1];
            if (ext === extension) {
                flag = false;
            }
        }
        if (!flag) {
            return;
        }
        throw error;
    });
};
Ritesh Toppo
  • 323
  • 1
  • 4
  • 13
-7

This is very much a hack, but works for quick stuff.

function wait (ms) {
    var now = Date.now();
    var later = now + ms;
    while (Date.now() < later) {
        // wait
    }
}
Jaredcheeda
  • 1,657
  • 17
  • 15