递归获取目录NodejS中的所有文件

Posted

技术标签:

【中文标题】递归获取目录NodejS中的所有文件【英文标题】:Get all files recursively in directories NodejS 【发布时间】:2017-05-18 16:08:18 【问题描述】:

我的功能有点问题。我想获取许多目录中的所有文件。目前,我可以检索传入参数的文件中的文件。我想检索作为参数传递的文件夹中每个文件夹的 html 文件。我将解释如果我输入参数“test”我会在“test”中检索文件,但我想检索“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();
                );
            

结果: [1,2,3]

谢谢!

【问题讨论】:

【参考方案1】:

虽然在某些情况下并不完美,但在很多情况下一定会有所帮助。

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 = `<YOUR BASE PATH HERE>/$path`;
    let foldersToScrape: string[] = [];
    const filePaths: string[] = [];

    addData([baseDirPath]);

    while (foldersToScrape.length !== 0) 
        addData(foldersToScrape);
    

    return filePaths;
;

【讨论】:

【参考方案2】:

使用 ES6 产出

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

【讨论】:

从未听说过这种语法和关键字【参考方案3】:

说到 npm 包 - 另一个简短的选择是使用 fs-readdir-recursive:

const read = require("fs-readdir-recursive");
const foundFiles = read("test");
console.log(foundFiles);

输出:

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

如果您只对具有特定扩展名的文件感兴趣(例如问题中提到的 .html),您可以使用 .endsWith() 过滤它们:

const filteredFiles = read("test").filter(item => item.endsWith(".html"));

【讨论】:

【参考方案4】:

一个基于globby的Promises解决方案:

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', 
  //   ... 
  // ]
)()

【讨论】:

【参考方案5】:

这是一个紧凑的纯函数,它返回目录中的所有路径(亲戚)。

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)]),
    ]
  , [])

【讨论】:

【参考方案6】:

如果您更愿意与 glob 同步工作,请使用他们的 documentation 中提到的 glob.sync() 函数。这是@Paul Mougel 提供但同步编写的等效示例:

const glob = require("glob");

var getDirectories = function (src) 
  return glob.sync(src + '/**/*');
;
var rest = getDirectories('test');
console.log(res);

【讨论】:

【参考方案7】:

我真的很喜欢 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);
    
  
;

【讨论】:

【参考方案8】:

看起来glob npm package 可以帮助您。以下是如何使用它的示例:

文件层次结构:

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

【讨论】:

我找到的最短路径 glob 会跳过点文件,这让我有点失望。如果我们无法通过简单的搜索获得点文件,那么这个包的目的是什么? @AsifAshraf 根据文档:You can make glob treat dots as normal characters by setting dot:true in the options. -- npmjs.com/package/glob【参考方案9】:

您可以使用循环遍历根文件夹的所有文件和目录,如果是目录,则进入其中并重复该过程。 考虑下面的代码:

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

【讨论】:

【参考方案10】:

使用现代 javascript (NodeJs 10),您可以使用异步生成器函数并使用 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()

【讨论】:

【参考方案11】:

打包到库中: 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'
    ,
  ]

【讨论】:

对我来说,只要运行 require 就会崩溃 nodemon。 @JCraine 有一个错字。它应该是递归的【参考方案12】:

我看过很多很长的答案,这有点浪费内存空间。有些还使用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/");

这是不言自明的。有一个输入目录,它会遍历它。如果其中一个项目也是一个目录,则通过该项目,依此类推。如果是文件,则添加数组的绝对路径。

希望这会有所帮助:]

【讨论】:

【参考方案13】:

我用打字稿做的很好,很容易理解

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

【讨论】:

我在 typescript+eslint 和最后几行的数组展平方面遇到了一些麻烦。所以我用array.reduce替换了最后的步骤。由于我们不能在 cmets 中发布多行代码,所以这里是一个单行代码 :) export const getFilesRecursively = (rootPath: string) =&gt; getAllSubFolders(rootPath).reduce((result, folder) =&gt; [...result, ...getFilesInFolder(folder)], [] as string[])【参考方案14】:
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 数组中的一些目录名称。

【讨论】:

【参考方案15】:

这是我的。像所有好的答案一样,很难理解:

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

【讨论】:

好的答案通常是最容易理解的 这个答案写得很好,并不难理解。有用。这不是很多代码。它是同步的,不像 glob。【参考方案16】:

我需要在一个 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);
    );

【讨论】:

【参考方案17】:

您也可以编写自己的代码,如下所示遍历目录:

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

【讨论】:

谢谢!但是如何在 res.send 中发送结果?请 @coco62 一旦你在函数中得到结果,你可以传递它而不是记录它。

以上是关于递归获取目录NodejS中的所有文件的主要内容,如果未能解决你的问题,请参考以下文章

Java非递归的方式获取目录中所有文件(包括目录)

javascript [node.js 8+]递归获取目录中的所有文件

获取目录中所有文件的列表(递归)

递归搜索目录中的文件

如何递归遍历目录,通过 node.js 中的套接字发送所有文件名?

java递归遍历目录获取所有文件及目录方案