Получить все файлы рекурсивно в каталогах NodejS

У меня небольшая проблема с моей функцией. Я хотел бы получить все файлы во многих каталогах. В настоящее время я могу получить файлы в файле, переданном в параметрах. Я хотел бы получить html-файлы каждой папки в папке, переданной в качестве параметра. Я объясню, если я укажу параметр «тест», я получаю файлы в «тесте», но я хотел бы получить «тест / 1 / *. Html», «тест / 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();
                });
            }

Результат: [1,2,3]

Спасибо !


person Community    schedule 04.01.2017    source источник


Ответы (15)


Похоже, вам поможет glob пакет npm. Вот пример того, как его использовать:

Файловая иерархия:

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

JS-код:

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

который отображает:

[ 'test/one.html',
  'test/test-nested',
  'test/test-nested/two.html' ]
person Paul Mougel    schedule 04.01.2017
comment
кратчайший путь, который я нашел - person Vlad; 19.04.2018
comment
Я был немного разочарован тем, что glob пропускает Dot Files. Какова цель этого пакета, если мы не можем получить точечные файлы с помощью простого поиска? - person Asif Ashraf; 31.10.2020
comment
@AsifAhraf согласно документации: You can make glob treat dots as normal characters by setting dot:true in the options. -- npmjs.com/package/glob - person Steven; 17.04.2021

Я видел много очень длинных ответов, и это пустая трата памяти. Некоторые также используют такие пакеты, как glob, но если вы не хотите зависеть от какого-либо пакета, вот мое решение.

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/");

Это довольно очевидно. Есть входной каталог, и он перебирает его. Если один из элементов также является каталогом, перейдите по нему и так далее. Если это файл, добавьте абсолютный путь к массиву.

Надеюсь, это помогло:]

person Smally    schedule 27.07.2020

Вот мой. Как и все хорошие ответы, это трудно понять:

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));
};
person user875234    schedule 26.11.2017
comment
Хорошие ответы обычно самые простые для понимания - person Dara Java; 13.07.2020
comment
Этот ответ хорошо написан, и его не так сложно понять. Оно работает. Это не так много кода. Это синхронно, в отличие от glob. - person Jared Updike; 15.11.2020

Мне очень понравилось решение Smally, но не понравился синтаксис.

То же решение, но немного легче читать:

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);
    }
  }
};
person arthurDent    schedule 13.02.2021

Использование доходности ES6

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

function *walkSync(dir) {
  const files = fs.readdirSync(dir, { withFileTypes: true });
  for (let i = 0; i < files.length; i++) {
    if (files[i].isDirectory()) {
      yield* walkSync(path.join(dir, files[i].name));
    } else {
      yield path.join(dir, files[i].name);
    }
  }
}

for (let i of walkSync(__dirname)) {
  console.log(i);
}
person Stephen    schedule 06.02.2021

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('');

Это заполнит filesCollection всеми файлами в каталоге и его подкаталогах (это рекурсивно). У вас есть возможность пропустить некоторые имена каталогов в массиве directoriesToSkip.

person vvn050    schedule 19.03.2018

Упакован в библиотеку: https://www.npmjs.com/package/node-recursive-directory

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

Список файлов:

const getFiles = require('node-recursive-directory');

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

Список файлов с проанализированными данными:

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

Вы получите что-то вроде этого:

  [
      ...,
      {
        fullpath: '/home/vvm/Downloads/images/Some/Some Image.jpg',
        filepath: '/home/vvm/Downloads/images/Some/',
        filename: 'Some Image.jpg',
        dirname: 'Some'
    },
  ]
person Vladimir Myagdeev    schedule 24.06.2020
comment
Для меня просто запуск require приводит к сбою nodemon. - person JCraine; 21.07.2020
comment
Там опечатка @JCraine. Это должно быть рекурсивно - person Siddharth; 18.05.2021

С современным JavaScript (NodeJs 10) вы можете использовать функцию асинхронного генератора и циклически проходить их, используя для ожидания...

// 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()
person mikabytes    schedule 16.10.2020

Вы также можете написать свой собственный код, как показано ниже, для перемещения по каталогу, как показано ниже:

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

Дополнительную информацию об этом можно найти здесь: http://www.codingdefined.com/2014/09/how-to-navigate-through-directories-in.html

person CodingDefined    schedule 05.01.2017
comment
Спасибо ! но как отправить результат в res.send? пожалуйста - person ; 05.01.2017
comment
@ coco62 Как только вы получите результат внутри функции, вы можете передать его вместо регистрации. - person CodingDefined; 06.01.2017

Мне нужно было что-то подобное в приложении Electron: получить все подпапки в заданной базовой папке, используя TypeScript, и придумал это:

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);
    });
}
person Ben    schedule 07.11.2017

Вы можете использовать цикл по всем файлам и каталогам корневой папки, если это каталог, то войдите в него и повторите процесс. Рассмотрим код ниже:

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
person Nitin Manocha    schedule 16.10.2020

Если вы предпочитаете работать синхронно с glob, используйте функцию glob.sync(), как указано в их документации. Вот эквивалентный пример, предоставленный @Paul Mougel, но написанный синхронно:

const glob = require("glob");

var getDirectories = function (src) {
  return glob.sync(src + '/**/*');
};
var rest = getDirectories('test');
console.log(res);
person Armando Hoyos    schedule 01.05.2021

Вот компактная чистая функция, которая возвращает все пути (родственные) в каталоге.

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)]),
    ]
  }, [])
person Corentin    schedule 17.06.2021

Решение с промисами на основе 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', 
  //   ... 
  // ]
})()

person CimChd    schedule 23.07.2021

Я сделал мой с машинописью, работает хорошо, довольно легко понять

    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);
    };
person Chris Sprance    schedule 03.11.2018
comment
У меня были проблемы с typescript+eslint и выравниванием массива в последних строках. Поэтому я заменил последние шаги на array.reduce. Так как мы не можем размещать многострочный код в комментариях, вот однострочный :) export const getFilesRecursively = (rootPath: string) => getAllSubFolders(rootPath).reduce((result, folder) => [...result, ...getFilesInFolder(folder)], [] as string[]) - person loopmode; 19.12.2019