【问题标题】:best way to get folder and file list in Javascript在Javascript中获取文件夹和文件列表的最佳方法
【发布时间】:2014-01-16 07:40:00
【问题描述】:

我正在使用 node-webkit,并试图让用户选择一个文件夹,然后我将返回该文件夹的目录结构并递归获取其子级。

我用这段代码(在 Angular 控制器中)相当简单地完成了这个工作。

var fs = require('fs');

$scope.explorer=[];
$scope.openFile = function(){
    $scope.explorer = [tree_entry($scope.path)];    
    get_folder($scope.path, $scope.explorer[0].children);
};

function get_folder(path, tree){
    fs.readdir(path, function(err,files){
        if (err) return console.log(err);

        files.forEach( function (file,idx){
            tree.push(tree_entry(file));
            fs.lstat(path+'/'+file,function(err,stats){
                if(err) return console.log(err);
                if(stats.isDirectory()){
                    get_folder(path+'/'+file,tree[idx].children);
                }
            });
        });
    });
    console.log($scope.explorer);

    return;
}

function tree_entry(entry){
    return { label : entry, children: []}
}

取一个包含 22 个子文件夹和大约 4 层深度的中等大小的文件夹,需要几分钟才能获得整个目录结构。

我在这里显然做错了什么吗?我不敢相信它需要这么长时间,因为我正在使用内置的 Node fs 方法。或者有没有办法在不触及每个文件的情况下获取目录的全部内容?

我希望能够对文件名一直使用 Angular 过滤器,并且可能也对内容使用,因此延迟处理整个树不太可能是可行的解决方案.

【问题讨论】:

  • 也许它正在获取 .. 作为一个文件。您可能应该放置一些 console.log 以了解更多关于正在发生的事情。
  • 你的意思是它正在打开每个文件?不,这似乎不是问题,我正要删除问题,结果如果我删除了 console.log 并放入一个输出到控制台一次的回调,事情发生得更快。
  • 我的意思是..,父目录,但那是一个远景。很好,你找到了解决方案
  • 你需要的是一个简单的遍历目录的递归遍历函数。 Google 是您的朋友。

标签: javascript node.js recursion filesystems


【解决方案1】:

在我的项目中,我使用此功能来获取大量文件。它非常快(把require("fs") 放出来让它更快):

var _getAllFilesFromFolder = function(dir) {

    var filesystem = require("fs");
    var results = [];

    filesystem.readdirSync(dir).forEach(function(file) {

        file = dir+'/'+file;
        var stat = filesystem.statSync(file);

        if (stat && stat.isDirectory()) {
            results = results.concat(_getAllFilesFromFolder(file))
        } else results.push(file);

    });

    return results;

};

用法很清楚:

_getAllFilesFromFolder(__dirname + "folder");

【讨论】:

  • 有没有办法以非递归方式做到这一点?
  • 'require' 函数未定义。
  • @Jacob 标签中有 node.js 是有原因的
  • @GeekyInt 您的目录结构中可能有一个符号链接指向包含文件夹。在这种情况下,您可以使用fs.lstat() 而不是fs.stat()
  • 对于使用 Node 的快速 fs.Dirent 对象的高效、非阻塞(异步)技术,我在此线程中添加了 an answer
【解决方案2】:

fs/promises 和 fs.Dirent

这是一个使用 Node 的快速 fs.Dirent 对象和 fs/promises 模块的高效、非阻塞 ls 程序。这种方法允许您跳过每条路径上浪费的 fs.existfs.stat 调用 -

// main.js
import { readdir } from "fs/promises"
import { join } from "path"

async function* ls (path = ".")
{ yield path
  for (const dirent of await readdir(path, { withFileTypes: true }))
    if (dirent.isDirectory())
      yield* ls(join(path, dirent.name))
    else
      yield join(path, dirent.name)
}

async function* empty () {}

async function toArray (iter = empty())
{ let r = []
  for await (const x of iter)
    r.push(x)
  return r
}

toArray(ls(".")).then(console.log, console.error)

让我们获取一些示例文件,以便我们可以看到 ls 工作 -

$ yarn add immutable     # (just some example package)
$ node main.js
[
  '.',
  'main.js',
  'node_modules',
  'node_modules/.yarn-integrity',
  'node_modules/immutable',
  'node_modules/immutable/LICENSE',
  'node_modules/immutable/README.md',
  'node_modules/immutable/contrib',
  'node_modules/immutable/contrib/cursor',
  'node_modules/immutable/contrib/cursor/README.md',
  'node_modules/immutable/contrib/cursor/__tests__',
  'node_modules/immutable/contrib/cursor/__tests__/Cursor.ts.skip',
  'node_modules/immutable/contrib/cursor/index.d.ts',
  'node_modules/immutable/contrib/cursor/index.js',
  'node_modules/immutable/dist',
  'node_modules/immutable/dist/immutable-nonambient.d.ts',
  'node_modules/immutable/dist/immutable.d.ts',
  'node_modules/immutable/dist/immutable.es.js',
  'node_modules/immutable/dist/immutable.js',
  'node_modules/immutable/dist/immutable.js.flow',
  'node_modules/immutable/dist/immutable.min.js',
  'node_modules/immutable/package.json',
  'package.json',
  'yarn.lock'
]

有关利用异步生成器的补充说明和其他方法,请参阅this Q&A

【讨论】:

    【解决方案3】:

    为什么要发明轮子?

    有一个非常流行的 NPM 包,它可以让你轻松完成类似的事情。

    var recursive = require("recursive-readdir");
    
    recursive("some/path", function (err, files) {
      // `files` is an array of file paths
      console.log(files);
    });
    

    了解更多:

    【讨论】:

    • 此解决方案不列出目录本身
    • 从这么简单的东西安装一个入口包似乎有点多
    【解决方案4】:

    我不喜欢仅仅为了处理这个简单的任务而将新包添加到我的项目中。

    而且,我尽量避免使用 RECURSIVE 算法……因为在大多数情况下,它比非递归算法要慢。

    所以我做了一个函数来获取所有文件夹内容(及其子文件夹)......非递归

    var getDirectoryContent = function(dirPath) {
        /* 
            get list of files and directories from given dirPath and all it's sub directories
            NON RECURSIVE ALGORITHM
            By. Dreamsavior
        */
        var RESULT = {'files':[], 'dirs':[]};
    
        var fs = fs||require('fs');
        if (Boolean(dirPath) == false) {
            return RESULT;
        }
        if (fs.existsSync(dirPath) == false) {
            console.warn("Path does not exist : ", dirPath);
            return RESULT;
        }
    
        var directoryList = []
        var DIRECTORY_SEPARATOR = "\\";
        if (dirPath[dirPath.length -1] !== DIRECTORY_SEPARATOR) dirPath = dirPath+DIRECTORY_SEPARATOR;
    
        directoryList.push(dirPath); // initial
    
        while (directoryList.length > 0) {
            var thisDir  = directoryList.shift(); 
            if (Boolean(fs.existsSync(thisDir) && fs.lstatSync(thisDir).isDirectory()) == false) continue;
    
            var thisDirContent = fs.readdirSync(thisDir);
            while (thisDirContent.length > 0) { 
                var thisFile  = thisDirContent.shift(); 
                var objPath = thisDir+thisFile
    
                if (fs.existsSync(objPath) == false) continue;
                if (fs.lstatSync(objPath).isDirectory()) { // is a directory
                    let thisDirPath = objPath+DIRECTORY_SEPARATOR; 
                    directoryList.push(thisDirPath);
                    RESULT['dirs'].push(thisDirPath);
    
                } else  { // is a file
                    RESULT['files'].push(objPath); 
    
                } 
            } 
    
        }
        return RESULT;
    }
    

    这个函数的唯一缺点是这是同步函数......你已经被警告了;)

    【讨论】:

      猜你喜欢
      • 2011-07-08
      • 2012-12-27
      • 2017-02-25
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 2011-08-27
      • 2019-02-08
      • 1970-01-01
      相关资源
      最近更新 更多