Nodejs get all files in directory recursively

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 !

asked Jan 4, 2017 at 11:22

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' ]

NearHuscarl

47.6k12 gold badges188 silver badges172 bronze badges

answered Jan 4, 2017 at 11:32

Paul MougelPaul Mougel

16.3k5 gold badges54 silver badges63 bronze badges

3

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 :]

answered Jul 27, 2020 at 8:25

SmallySmally

1,2161 gold badge7 silver badges22 bronze badges

1

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];
}

answered Feb 6, 2021 at 23:31

StephenStephen

3,2181 gold badge21 silver badges20 bronze badges

2

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];
    }
  }
};

answered Feb 13, 2021 at 16:07

arthurDentarthurDent

6257 silver badges10 bronze badges

1

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]];
};

answered Nov 26, 2017 at 2:45

user875234user875234

2,2536 gold badges28 silver badges45 bronze badges

3

With modern JavaScript [NodeJs 10] you can use async generator function and loop through them using for-await...of

// ES modules syntax that is included by default in NodeJS 14.
// For earlier versions, use `--experimental-modules` flag
import fs from "fs/promises"

// or, without ES modules, use this:
// const fs = require['fs'].promises

async function run[] {
  for await [const file of getFiles[]] {
    console.log[file.path]
  }
}

async function* getFiles[path = `./`] {
  const entries = await fs.readdir[path, { withFileTypes: true }]

  for [let file of entries] {
    if [file.isDirectory[]] {
      yield* getFiles[`${path}${file.name}/`]
    } else {
      yield { ...file, path: path + file.name }
    }
  }
}

run[]

answered Oct 16, 2020 at 8:22

mikabytesmikabytes

1,7282 gold badges17 silver badges29 bronze badges

2

Packed into library: //www.npmjs.com/package/node-recursive-directory

//github.com/vvmspace/node-recursive-directory

List of files:

const getFiles = require['node-recursive-directory'];

[async [] => {
    const files = await getFiles['/home'];
    console.log[files];
}][]

List of files with parsed data:

const getFiles = require['node-resursive-directory'];
 
[async [] => {
    const files = await getFiles['/home', true]; // add true
    console.log[files];
}][]

You will get something like that:

  [
      ...,
      {
        fullpath: '/home/vvm/Downloads/images/Some/Some Image.jpg',
        filepath: '/home/vvm/Downloads/images/Some/',
        filename: 'Some Image.jpg',
        dirname: 'Some'
    },
  ]

Max

6,4563 gold badges41 silver badges57 bronze badges

answered Jun 24, 2020 at 14:42

2

You can also write your own code like below to traverse the directory as shown below :

var fs = require['fs'];
function traverseDirectory[dirname, callback] {
  var directory = [];
  fs.readdir[dirname, function[err, list] {
    dirname = fs.realpathSync[dirname];
    if [err] {
      return callback[err];
    }
    var listlength = list.length;
    list.forEach[function[file] {
      file = dirname + '\\' + file;
      fs.stat[file, function[err, stat] {
        directory.push[file];
 if [stat && stat.isDirectory[]] {
          traverseDirectory[file, function[err, parsed] {
     directory = directory.concat[parsed];
     if [!--listlength] {
       callback[null, directory];
     }
   }];
 } else {
     if [!--listlength] {
       callback[null, directory];
     }
          }
      }];
    }];
  }];
}
traverseDirectory[__dirname, function[err, result] {
  if [err] {
    console.log[err];
  }
  console.log[result];
}];

You can check more information about it here : //www.codingdefined.com/2014/09/how-to-navigate-through-directories-in.html

answered Jan 5, 2017 at 11:13

CodingDefinedCodingDefined

1,9621 gold badge15 silver badges13 bronze badges

2

I needed to so something similar, in an Electron app: get all subfolders in a given base folder, using TypeScript, and came up with this:

import { readdirSync, statSync, existsSync } from "fs";
import * as path from "path";

// recursive synchronous "walk" through a folder structure, with the given base path
getAllSubFolders = [baseFolder, folderList = []] => {

    let folders:string[] = readdirSync[baseFolder].filter[file => statSync[path.join[baseFolder, file]].isDirectory[]];
    folders.forEach[folder => {
        folderList.push[path.join[baseFolder,folder]];
        this.getAllSubFolders[path.join[baseFolder,folder], folderList];
    }];
}

answered Nov 7, 2017 at 15:09

BenBen

1,1292 gold badges17 silver badges26 bronze badges

const fs = require['fs'];
const path = require['path'];
var filesCollection = [];
const directoriesToSkip = ['bower_components', 'node_modules', 'www', 'platforms'];

function readDirectorySynchronously[directory] {
    var currentDirectorypath = path.join[__dirname + directory];

    var currentDirectory = fs.readdirSync[currentDirectorypath, 'utf8'];

    currentDirectory.forEach[file => {
        var fileShouldBeSkipped = directoriesToSkip.indexOf[file] > -1;
        var pathOfCurrentItem = path.join[__dirname + directory + '/' + file];
        if [!fileShouldBeSkipped && fs.statSync[pathOfCurrentItem].isFile[]] {
            filesCollection.push[pathOfCurrentItem];
        }
        else if [!fileShouldBeSkipped] {
            var directorypath = path.join[directory + '\\' + file];
            readDirectorySynchronously[directorypath];
        }
    }];
}

readDirectorySynchronously[''];

This will fill filesCollection with all the files in the directory and its subdirectories [it's recursive]. You have the option to skip some directory names in the directoriesToSkip array.

answered Mar 19, 2018 at 12:54

vvn050vvn050

1191 silver badge3 bronze badges

Speaking of npm packages - another short option is to use fs-readdir-recursive:

const read = require["fs-readdir-recursive"];
const foundFiles = read["test"];
console.log[foundFiles];

Output:

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

If you're interested only in files with specific extension [like .html mentioned in the question] you can filter them using .endsWith[]:

const filteredFiles = read["test"].filter[item => item.endsWith[".html"]];

answered Aug 11, 2021 at 10:05

ZukuZuku

80010 silver badges20 bronze badges

If you rather work synchronously with glob, use the glob.sync[] function as mentioned in their documentation. Here's the equivalent example provided by @Paul Mougel but written synchronously:

const glob = require["glob"];

var getDirectories = function [src] {
  return glob.sync[src + '/**/*'];
};
var rest = getDirectories['test'];
console.log[res];

answered May 1, 2021 at 16:56

You can use loop through all the files and directories of the root folder, if it's a directory, then get inside it and repeat the process. Consider the code below:

const fs = require['fs'];
const path = require['path'];

const target = './'; // choose the directory to target
var result = []
var filePaths = []
var tempFolder = []
const targetPath = fs.readdirSync[target];




function hit[mainPath = targetPath] {

  mainPath.forEach[[file] => {

    let check = fs.statSync[file];

    if [!check.isDirectory[]] {
      filePaths.push[file]
    }
    else {
      if [file[0] != '.'] {
        tempFolder.push[file]
      }
    }
  }];

  // get files from folder
  if [tempFolder.length > 0] {
    tempFolder.forEach[[dir] => {
      getFiles[dir]
    }]
  } 
   // filePaths contains path to every file

}




function getFiles[dir] {

  var paths = fs.readdirSync[dir];
  var files = [];

  paths.forEach[function [file] {
    var fullPath = dir + '/' + file;
    files.push[fullPath];
  }];

  files.forEach[[tempFile] => {
    let check = fs.statSync[tempFile];

    if [check.isDirectory[]] {
      getFiles[tempFile]
    } else {
      filePaths.push[tempFile]
    }
  }]
}



hit[]; // main function

answered Oct 16, 2020 at 9:32

A solution with Promises based on globby:

import { globby } from 'globby';

[async [] => {
  const path = '/path/to/dir';
  const files = await globby[[`${path}/**/*`]];

  console.log[files];
  // [ 
  //   '/path/to/dir/file1.txt', 
  //   '/path/to/dir/subdir/file2.txt', 
  //   ... 
  // ]
}][]

answered Jul 23, 2021 at 17:11

Although not perfect in some scenarios, it must be helpful in many.

const getAllFilePath = [path: string] => {
    const addData = [_paths: string[]] => {
        const newFoldersToScrape: string[] = [];

        _paths.forEach[_path => {
            fs.readdirSync[_path].forEach[[file: string] => {
                if [file.indexOf["."] === -1] {
                    newFoldersToScrape.push[`${_path}/${file}`];
                } else {
                    filePaths.push[`${_path}/${file}`];
                }
            }];
        }];

        foldersToScrape = newFoldersToScrape;
    };

    const baseDirPath = `/${path}`;
    let foldersToScrape: string[] = [];
    const filePaths: string[] = [];

    addData[[baseDirPath]];

    while [foldersToScrape.length !== 0] {
        addData[foldersToScrape];
    }

    return filePaths;
};

answered Feb 12 at 11:19

Here is a compact pure function that returns all the paths [relatives] in the directory.

import path from 'path'

const getFilesPathsRecursively = [directory: string, origin?: string]: string[] =>
  fs.readdirSync[directory].reduce[[files, file] => {
    const absolute = path.join[directory, file]
    return [
      ...files,
      ...[fs.statSync[absolute].isDirectory[]
        ? getFilesPathsRecursively[absolute, origin || directory]
        : [path.relative[origin || directory, absolute]]],
    ]
  }, []]

answered Jun 17, 2021 at 13:07

2

I did mine with typescript works well fairly easy to understand

    import * as fs from 'fs';
    import * as path from 'path';

    export const getAllSubFolders = [
      baseFolder: string,
      folderList: string[] = []
    ] => {
      const folders: string[] = fs
        .readdirSync[baseFolder]
        .filter[file => fs.statSync[path.join[baseFolder, file]].isDirectory[]];
      folders.forEach[folder => {
        folderList.push[path.join[baseFolder, folder]];
        getAllSubFolders[path.join[baseFolder, folder], folderList];
      }];
      return folderList;
    };
    export const getFilesInFolder = [rootPath: string] => {
      return fs
        .readdirSync[rootPath]
        .filter[
          filePath => !fs.statSync[path.join[rootPath, filePath]].isDirectory[]
        ]
        .map[filePath => path.normalize[path.join[rootPath, filePath]]];
    };
    export const getFilesRecursively = [rootPath: string] => {
      const subFolders: string[] = getAllSubFolders[rootPath];
      const allFiles: string[][] = subFolders.map[folder =>
        getFilesInFolder[folder]
      ];
      return [].concat.apply[[], allFiles];
    };

answered Nov 3, 2018 at 17:11

1

Chủ Đề