Search code examples
javascriptarraysnode.jsloopsfs

Looping through files in a folder Node.JS


I am trying to loop through and pick up files in a directory, but I have some trouble implementing it. How to pull in multiple files and then move them to another folder?

var dirname = 'C:/FolderwithFiles';
console.log("Going to get file info!");
fs.stat(dirname, function (err, stats) {
    if (err) {
        return console.error(err);
    }
    console.log(stats);
    console.log("Got file info successfully!");

    // Check file type
    console.log("isFile ? " + stats.isFile());
    console.log("isDirectory ? " + stats.isDirectory());
});

Solution

  • Older answer with callbacks

    You want to use the fs.readdir function to get the directory contents and the fs.rename function to actually do the renaming. Both these functions have synchronous versions if you need to wait for them to finishing before running the code afterwards.

    I wrote a quick script that does what you described.

    var fs = require('fs');
    var path = require('path');
    // In newer Node.js versions where process is already global this isn't necessary.
    var process = require("process");
    
    var moveFrom = "/home/mike/dev/node/sonar/moveme";
    var moveTo = "/home/mike/dev/node/sonar/tome"
    
    // Loop through all the files in the temp directory
    fs.readdir(moveFrom, function (err, files) {
      if (err) {
        console.error("Could not list the directory.", err);
        process.exit(1);
      }
    
      files.forEach(function (file, index) {
        // Make one pass and make the file complete
        var fromPath = path.join(moveFrom, file);
        var toPath = path.join(moveTo, file);
    
        fs.stat(fromPath, function (error, stat) {
          if (error) {
            console.error("Error stating file.", error);
            return;
          }
    
          if (stat.isFile())
            console.log("'%s' is a file.", fromPath);
          else if (stat.isDirectory())
            console.log("'%s' is a directory.", fromPath);
    
          fs.rename(fromPath, toPath, function (error) {
            if (error) {
              console.error("File moving error.", error);
            } else {
              console.log("Moved file '%s' to '%s'.", fromPath, toPath);
            }
          });
        });
      });
    });
    

    Tested on my local machine.

    node testme.js 
    '/home/mike/dev/node/sonar/moveme/hello' is a file.
    '/home/mike/dev/node/sonar/moveme/test' is a directory.
    '/home/mike/dev/node/sonar/moveme/test2' is a directory.
    '/home/mike/dev/node/sonar/moveme/test23' is a directory.
    '/home/mike/dev/node/sonar/moveme/test234' is a directory.
    Moved file '/home/mike/dev/node/sonar/moveme/hello' to '/home/mike/dev/node/sonar/tome/hello'.
    Moved file '/home/mike/dev/node/sonar/moveme/test' to '/home/mike/dev/node/sonar/tome/test'.
    Moved file '/home/mike/dev/node/sonar/moveme/test2' to '/home/mike/dev/node/sonar/tome/test2'.
    Moved file '/home/mike/dev/node/sonar/moveme/test23' to '/home/mike/dev/node/sonar/tome/test23'.
    Moved file '/home/mike/dev/node/sonar/moveme/test234' to '/home/mike/dev/node/sonar/tome/test234'.
    

    Update: fs.promises functions with async/await

    Inspired by ma11hew28's answer (shown here), here is the same thing as above but with the async functions in fs.promises. As noted by ma11hew28, this may have memory limitations versus fs.promises.opendir added in v12.12.0.

    Quick code below.

    //jshint esversion:8
    //jshint node:true
    const fs = require( 'fs' );
    const path = require( 'path' );
    
    const moveFrom = "/tmp/movefrom";
    const moveTo = "/tmp/moveto";
    
    // Make an async function that gets executed immediately
    (async ()=>{
        // Our starting point
        try {
            // Get the files as an array
            const files = await fs.promises.readdir( moveFrom );
    
            // Loop them all with the new for...of
            for( const file of files ) {
                // Get the full paths
                const fromPath = path.join( moveFrom, file );
                const toPath = path.join( moveTo, file );
    
                // Stat the file to see if we have a file or dir
                const stat = await fs.promises.stat( fromPath );
    
                if( stat.isFile() )
                    console.log( "'%s' is a file.", fromPath );
                else if( stat.isDirectory() )
                    console.log( "'%s' is a directory.", fromPath );
    
                // Now move async
                await fs.promises.rename( fromPath, toPath );
    
                // Log because we're crazy
                console.log( "Moved '%s'->'%s'", fromPath, toPath );
            } // End for...of
        }
        catch( e ) {
            // Catch anything bad that happens
            console.error( "We've thrown! Whoops!", e );
        }
    
    })(); // Wrap in parenthesis and call now