Get all files recursively in directories NodejS

78,570

Solution 1

It looks like the glob npm package would help you. Here is an example of how to use it:

File hierarchy:

test
├── one.html
└── test-nested
    └── two.html

JS code:

const glob = require("glob");

var getDirectories = function (src, callback) {
  glob(src + '/**/*', callback);
};
getDirectories('test', function (err, res) {
  if (err) {
    console.log('Error', err);
  } else {
    console.log(res);
  }
});

which displays:

[ 'test/one.html',
  'test/test-nested',
  'test/test-nested/two.html' ]

Solution 2

I've seen many very long answers, and it's kinda a waste of memory space. Some also use packages like glob, but if you don't want to depend on any package, here's my solution.

const Path = require("path");
const FS   = require("fs");
let Files  = [];

function ThroughDirectory(Directory) {
    FS.readdirSync(Directory).forEach(File => {
        const Absolute = Path.join(Directory, File);
        if (FS.statSync(Absolute).isDirectory()) return ThroughDirectory(Absolute);
        else return Files.push(Absolute);
    });
}

ThroughDirectory("./input/directory/");

It's pretty self-explanatory. There's an input directory, and it iterates through that. If one of the items is also a directory, go through that and so on. If it's a file, add the absolute path to the array.

Hope this helped :]

Solution 3

Using ES6 yield

const fs = require('fs');
const path = require('path');

function *walkSync(dir) {
  const files = fs.readdirSync(dir, { withFileTypes: true });
  for (const file of files) {
    if (file.isDirectory()) {
      yield* walkSync(path.join(dir, file.name));
    } else {
      yield path.join(dir, file.name);
    }
  }
}

for (const filePath of walkSync(__dirname)) {
  console.log(filePath);
}

Solution 4

Here's mine. Like all good answers it's hard to understand:

const isDirectory = path => statSync(path).isDirectory();
const getDirectories = path =>
    readdirSync(path).map(name => join(path, name)).filter(isDirectory);

const isFile = path => statSync(path).isFile();  
const getFiles = path =>
    readdirSync(path).map(name => join(path, name)).filter(isFile);

const getFilesRecursively = (path) => {
    let dirs = getDirectories(path);
    let files = dirs
        .map(dir => getFilesRecursively(dir)) // go through each directory
        .reduce((a,b) => a.concat(b), []);    // map returns a 2d array (array of file arrays) so flatten
    return files.concat(getFiles(path));
};

Solution 5

I really liked Smally's Solution but didn't like the Syntax.

Same solution but slightly easier to read:

const fs = require("fs");
const path = require("path");
let files = [];

const getFilesRecursively = (directory) => {
  const filesInDirectory = fs.readdirSync(directory);
  for (const file of filesInDirectory) {
    const absolute = path.join(directory, file);
    if (fs.statSync(absolute).isDirectory()) {
        getFilesRecursively(absolute);
    } else {
        files.push(absolute);
    }
  }
};
Share:
78,570
Admin
Author by

Admin

Updated on February 13, 2022

Comments

  • Admin
    Admin over 2 years

    I have a little problem with my function. I would like to get all files in many directories. Currently, I can retrieve the files in the file passed in parameters. I would like to retrieve the html files of each folder in the folder passed as a parameter. I will explain if I put in parameter "test" I retrieve the files in "test" but I would like to retrieve "test / 1 / *. Html", "test / 2 / . /.html ":

    var srcpath2 = path.join('.', 'diapo', result);
    function getDirectories(srcpath2) {
                    return fs.readdirSync(srcpath2).filter(function (file) {
                        return fs.statSync(path.join(srcpath2, file)).isDirectory();
                    });
                }
    

    The result : [1,2,3]

    thanks !

  • Admin
    Admin over 7 years
    thanks ! but how send the result in res.send ? please
  • CodingDefined
    CodingDefined over 7 years
    @coco62 Once you get the result inside the function, you can pass that instead of logging it.
  • Vlad
    Vlad about 6 years
    the shortest way i found
  • loopmode
    loopmode over 4 years
    I had some trouble with typescript+eslint and the flattening of the array in the last lines. So I replaced the last steps by array.reduce. Since we can't post multiline code in comments, here's a single-liner :) export const getFilesRecursively = (rootPath: string) => getAllSubFolders(rootPath).reduce((result, folder) => [...result, ...getFilesInFolder(folder)], [] as string[])
  • Dara Java
    Dara Java almost 4 years
    Good answers are usually the most simple to understand
  • JCraine
    JCraine almost 4 years
    For me, just running the require crashes nodemon.
  • Asif Ashraf
    Asif Ashraf over 3 years
    I was little disappointed that glob will skip Dot Files. What is the purpose of this package if we cannot get dotfiles with simple search?
  • Jared Updike
    Jared Updike over 3 years
    This answer is well written and not that hard to understand. It works. It is not a lot of code. It is synchronous, unlike glob.
  • Steven
    Steven about 3 years
    @AsifAshraf per the documentation: You can make glob treat dots as normal characters by setting dot:true in the options. -- npmjs.com/package/glob
  • Siddharth Shyniben
    Siddharth Shyniben about 3 years
    There's a typo @JCraine. It should be recursive
  • GorvGoyl
    GorvGoyl over 2 years
    never heard of this syntax and keyword
  • Avin Kavish
    Avin Kavish about 2 years
    Instead of statSync now you can load all stats in one call. const dirs = await readdir('./', { withFileTypes: true })
  • Alexey Khachatryan
    Alexey Khachatryan about 2 years
    const fetchAllFilesFromGivenFolder = (fullPath) => { let files = []; fs.readdirSync(fullPath).forEach(file => { const absolutePath = path.join(fullPath, file); if (fs.statSync(absolutePath).isDirectory()) { const filesFromNestedFolder = fetchAllFilesFromGivenFolder(absolutePath); filesFromNestedFolder.forEach(file => { files.push(file); }) } else return files.push(absolutePath); }); return files }