如何在 Node.js 中获取目录中所有文件的名称列表?

I'm trying to get a list of the names of all the files present in a directory using Node.js. I want output that is an array of filenames. How can I do this?

转载于:https://stackoverflow.com/questions/2727167/how-do-you-get-a-list-of-the-names-of-all-files-present-in-a-directory-in-node-j

csdnceshi71
Memor.の es7 method with await here
3 年多之前 回复
csdnceshi62
csdnceshi62 Checkout NPM's readdir-recursive module though if you're looking for the names of files in subdirectories also
4 年多之前 回复
csdnceshi50
三生石@ fs.readdir works, but cannot use file name glob patterns like ls /tmp/*core*. Check out github.com/isaacs/node-glob. Globs can even search in sub-directories.
接近 7 年之前 回复

16个回答

You can use the fs.readdir or fs.readdirSync methods.

fs.readdir

const testFolder = './tests/';
const fs = require('fs');

fs.readdir(testFolder, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
})

fs.readdirSync

const testFolder = './tests/';
const fs = require('fs');

fs.readdirSync(testFolder).forEach(file => {
  console.log(file);
})

The difference between the two methods, is that the first one is asynchronous, so you have to provide a callback function that will be executed when the read process ends.

The second is synchronous, it will return the file name array, but it will stop any further execution of your code until the read process ends.

csdnceshi78
程序go PS. update your example with fs.promises (v10)
大约 2 年之前 回复
weixin_41568126
乱世@小熊 yeah recently found out that ls isn't really good for file lists. But find is pretty good at it :)
大约 3 年之前 回复
csdnceshi76
斗士狗 You want to try parsing the output of ls? Just wait until somebody creates some filenames with embedded spaces and newlines…
大约 3 年之前 回复
weixin_41568126
乱世@小熊 I'm confused... Wouldn't it be better to use ls or dir /b/s for this job? Would have thought these methods would be much faster than iterating in Node...
3 年多之前 回复
csdnceshi80
胖鸭 For the newer promise method see my answer.
4 年多之前 回复
weixin_41568131
10.24 unless you're using gulp to read in a directory of source order dependant files and compile them into a single executable.
4 年多之前 回复
csdnceshi60
℡Wang Yan I should add that most probably you should go with readdire because you dont want to block IO in node.
接近 5 年之前 回复
csdnceshi70
笑故挽风 Note: readdir also shows directory names. To filter these, use fs.stat(path, callback(err, stats)) and stats.isDirectory().
8 年多之前 回复

The answer above does not perform a recursive search into the directory though. Here's what I did for a recursive search (using node-walk: npm install walk)

var walk    = require('walk');
var files   = [];

// Walker options
var walker  = walk.walk('./test', { followLinks: false });

walker.on('file', function(root, stat, next) {
    // Add this file to the list of files
    files.push(root + '/' + stat.name);
    next();
});

walker.on('end', function() {
    console.log(files);
});
csdnceshi77
狐狸.fox just want to say, the idea of using a npm module to "walk into sub directories" is completely ridiculous. It's a dead simple recursive function.
2 年多之前 回复
csdnceshi56
lrony* > unless you are willing to write your own routine to do just that, which you don't given that there are already npm modules out there to solve this very problem Yeah, you don't want to write left-pad yourself too when there's a package for that! :/
3 年多之前 回复
weixin_41568196
撒拉嘿哟木头 For the newer ES7 method see my answer.
4 年多之前 回复
csdnceshi54
hurriedly% This is a fantastic function. Quick question: is there a quick way to ignore certain dirs? I want to ignore directories starting with .git
4 年多之前 回复
csdnceshi79
python小菜 OP did not ask about which API does a recursive read. In any case, the accepted answer provides what can also serve as a basis for making a recursive read.
大约 5 年之前 回复
csdnceshi61
derek5. Here is a link to the walk github repo + docs: github.com/coolaj86/node-walk
大约 8 年之前 回复
csdnceshi65
larry*wei fs.readdirSync doesn't walk into sub directories unfortunately, unless you are willing to write your own routine to do just that, which you don't given that there are already npm modules out there to solve this very problem.
8 年多之前 回复
csdnceshi76
斗士狗 fs.readdirSync is better, native alternative created specially for this.
8 年多之前 回复

IMO the most convinient way to do such tasks is to use a glob tool. Here's a glob package for node.js. Install with

npm install glob

Then use wild card to match filenames (example taken from package's website)

var glob = require("glob")

// options is optional
glob("**/*.js", options, function (er, files) {
  // files is an array of filenames.
  // If the `nonull` option is set, and nothing
  // was found, then files is ["**/*.js"]
  // er is an error object or null.
})
weixin_41568134
MAO-EYE For people like me looking for a glob implementation using Promises, check out globby by sindresorhus: github.com/sindresorhus/globby
2 年多之前 回复
csdnceshi75
衫裤跑路 The glob.sync(pattern, [options]) method may be easier to use as it simply returns an array of file names, rather than using a callback. More info here: github.com/isaacs/node-glob
4 年多之前 回复
csdnceshi59
ℙℕℤℝ How can get the results of glob outside of itself? Eg. I want to console.log the results, but not inside glob()?
4 年多之前 回复
csdnceshi67
bug^君 I like this one too just because globbing is almost a fundamental skill in node. If you want to just get filenames back, pass in a cwd in the options object.
大约 5 年之前 回复
weixin_41568126
乱世@小熊 most elegant solution in my opinion because it is simple and familiar. Thanks
5 年多之前 回复
csdnceshi52
妄徒之命 this was the best solution for me as i wanted to specify filetype easier than string comparisons. Thanks.
接近 6 年之前 回复

Get files in all subdirs

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}

console.log(getFiles('path/to/dir'))
csdnceshi80
胖鸭 You forgot to add var fs = require('fs'); at the start of getFiles.
大约 5 年之前 回复
csdnceshi50
三生石@ Why if (typeof files_ === 'undefined') files_=[];? you only need to do var files_ = files_ || []; instead of files_ = files_ || [];.
接近 6 年之前 回复
csdnceshi77
狐狸.fox It clearly does return a list of files.
6 年多之前 回复

Get sorted filenames. You can filter results based on a specific extension such as '.txt', '.jpg' and so on.

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

function getFilenames(path, extension) {
    return fs
        .readdirSync(path)
        .filter(
            item =>
                fs.statSync(Path.join(path, item)).isFile() &&
                (extension === undefined || Path.extname(item) === extension)
        )
        .sort();
}

Took the general approach of @Hunan-Rostomyan, made it a litle more concise and added excludeDirs argument. It'd be trivial to extend with includeDirs, just follow same pattern:

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

function fileList(dir, excludeDirs?) {
    return fs.readdirSync(dir).reduce(function (list, file) {
        const name = path.join(dir, file);
        if (fs.statSync(name).isDirectory()) {
            if (excludeDirs && excludeDirs.length) {
                excludeDirs = excludeDirs.map(d => path.normalize(d));
                const idx = name.indexOf(path.sep);
                const directory = name.slice(0, idx === -1 ? name.length : idx);
                if (excludeDirs.indexOf(directory) !== -1)
                    return list;
            }
            return list.concat(fileList(name, excludeDirs));
        }
        return list.concat([name]);
    }, []);
}

Example usage:

console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
csdnceshi58
Didn"t forge Only works fine with '.' folder directory, with the rest directories doesn't works.
4 年多之前 回复
csdnceshi58
Didn"t forge I have a main folder: scss, and inside it other folder: themes, but the final list give me all directories, not only directories without exclude directorie, whats happen?
4 年多之前 回复

Load fs:

const fs = require('fs');

Read files async:

fs.readdir('./dir', function (err, files) {
    // "files" is an Array with files names
});

Read files sync:

var files = fs.readdirSync('./dir');

Here's a simple solution using only the native fs and path modules:

// sync version
function walkSync(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdirSync(currentDirPath).forEach(function (name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walkSync(filePath, callback);
        }
    });
}

or async version (uses fs.readdir instead):

// async version with basic error handling
function walk(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdir(currentDirPath, function (err, files) {
        if (err) {
            throw new Error(err);
        }
        files.forEach(function (name) {
            var filePath = path.join(currentDirPath, name);
            var stat = fs.statSync(filePath);
            if (stat.isFile()) {
                callback(filePath, stat);
            } else if (stat.isDirectory()) {
                walk(filePath, callback);
            }
        });
    });
}

Then you just call (for sync version):

walkSync('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

or async version:

walk('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

The difference is in how node blocks while performing the IO. Given that the API above is the same, you could just use the async version to ensure maximum performance.

However there is one advantage to using the synchronous version. It is easier to execute some code as soon as the walk is done, as in the next statement after the walk. With the async version, you would need some extra way of knowing when you are done. Perhaps creating a map of all paths first, then enumerating them. For simple build/util scripts (vs high performance web servers) you could use the sync version without causing any damage.

weixin_41568127
?yb? This is really helpful, and this method is recursive. Thanks!
3 年多之前 回复
csdnceshi64
游.程 But you're still using fs.statSync, which blocks, in async version. Shouldn't you be using fs.stat instead?
4 年多之前 回复
weixin_41568208
北城已荒凉 thanks, i've updated the sample
4 年多之前 回复
weixin_41568183
零零乙 Should replace the line in walkSync from walk(filePath, callback); to walkSync(filePath, callback);
4 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 Should be ok now, right?
5 年多之前 回复

Using Promises with ES7

Asynchronous use with mz/fs

The mz module provides promisified versions of the core node library. Using them is simple. First install the library...

npm install mz

Then...

const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
  .catch(err => console.error(err));

Alternatively you can write them in asynchronous functions in ES7:

async function myReaddir () {
  try {
    const file = await fs.readdir('./myDir/');
  }
  catch (err) { console.error( err ) }
};

Update for recursive listing

Some of the users have specified a desire to see a recursive listing (though not in the question)... Use fs-promise. It's a thin wrapper around mz.

npm install fs-promise;

then...

const fs = require('fs-promise');
fs.walk('./myDir').then(
    listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
csdnceshi66
必承其重 | 欲带皇冠 fs.walk is removed from fs-promise as it it not supported by fs ( github.com/kevinbeaty/fs-promise/issues/28 )
3 年多之前 回复

Here's an asynchronous recursive version.

    function ( path, callback){
     // the callback gets ( err, files) where files is an array of file names
     if( typeof callback !== 'function' ) return
     var
      result = []
      , files = [ path.replace( /\/\s*$/, '' ) ]
     function traverseFiles (){
      if( files.length ) {
       var name = files.shift()
       fs.stat(name, function( err, stats){
        if( err ){
         if( err.errno == 34 ) traverseFiles()
    // in case there's broken symbolic links or a bad path
    // skip file instead of sending error
         else callback(err)
        }
        else if ( stats.isDirectory() ) fs.readdir( name, function( err, files2 ){
         if( err ) callback(err)
         else {
          files = files2
           .map( function( file ){ return name + '/' + file } )
           .concat( files )
          traverseFiles()
         }
        })
        else{
         result.push(name)
         traverseFiles()
        }
       })
      }
      else callback( null, result )
     }
     traverseFiles()
    }
csdnceshi74
7*4 Get into the habit of adding semicolons to the end of your statements. You can't minify code otherwise. Nevertheless, thanks for the much needed async contribution.
大约 5 年之前 回复
共16条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐