これが単純なことになることを願っていましたが、それをするためにそこに何か見つけることはできません。
特定のフォルダ/ディレクトリ内のすべてのフォルダ/ディレクトリを取得したいだけです。
だから、例えば:
<MyFolder>
|- SomeFolder
|- SomeOtherFolder
|- SomeFile.txt
|- SomeOtherFile.txt
|- x-directory
私はの配列を取得することを期待します:
["SomeFolder", "SomeOtherFolder", "x-directory"]
それが提供された方法だった場合それともパスと上記のまたは...
それで、上記をするために何かが既に存在しますか?
これは、現在のディレクトリ内の(隠されているかどうかにかかわらず)すべてのディレクトリを一覧表示できる この答え のより短い同期バージョンです。
const { lstatSync, readdirSync } = require('fs')
const { join } = require('path')
const isDirectory = source => lstatSync(source).isDirectory()
const getDirectories = source =>
readdirSync(source).map(name => join(source, name)).filter(isDirectory)
JavaScript ES6(ES2015)の構文機能のおかげで、これは1つの裏付けになります。
同期バージョン
const { readdirSync, statSync } = require('fs')
const { join } = require('path')
const dirs = p => readdirSync(p).filter(f => statSync(join(p, f)).isDirectory())
Node.js 10+の非同期バージョン(実験的)
const { readdir, stat } = require("fs").promises
const { join } = require("path")
const dirs = async path => {
let dirs = []
for (const file of await readdir(path)) {
if ((await stat(join(path, file))).isDirectory()) {
dirs = [...dirs, file]
}
}
return dirs
}
パスを使用してディレクトリを一覧表示します。
function getDirectories(path) {
return fs.readdirSync(path).filter(function (file) {
return fs.statSync(path+'/'+file).isDirectory();
});
}
私はここにすべてのサブディレクトリ、およびそれらのすべてのサブディレクトリなどを取得する方法を探して来ました。 受け入れられた答え に基づいて、私はこれを書きました:
const fs = require('fs');
const path = require('path');
function flatten(lists) {
return lists.reduce((a, b) => a.concat(b), []);
}
function getDirectories(srcpath) {
return fs.readdirSync(srcpath)
.map(file => path.join(srcpath, file))
.filter(path => fs.statSync(path).isDirectory());
}
function getDirectoriesRecursive(srcpath) {
return [srcpath, ...flatten(getDirectories(srcpath).map(getDirectoriesRecursive))];
}
これはそれをするはずです:
CoffeeScript(sync)
fs = require 'fs'
getDirs = (rootDir) ->
files = fs.readdirSync(rootDir)
dirs = []
for file in files
if file[0] != '.'
filePath = "#{rootDir}/#{file}"
stat = fs.statSync(filePath)
if stat.isDirectory()
dirs.Push(file)
return dirs
CoffeeScript(async)
fs = require 'fs'
getDirs = (rootDir, cb) ->
fs.readdir rootDir, (err, files) ->
dirs = []
for file, index in files
if file[0] != '.'
filePath = "#{rootDir}/#{file}"
fs.stat filePath, (err, stat) ->
if stat.isDirectory()
dirs.Push(file)
if files.length == (index + 1)
cb(dirs)
JavaScript(async)
var fs = require('fs');
var getDirs = function(rootDir, cb) {
fs.readdir(rootDir, function(err, files) {
var dirs = [];
for (var index = 0; index < files.length; ++index) {
var file = files[index];
if (file[0] !== '.') {
var filePath = rootDir + '/' + file;
fs.stat(filePath, function(err, stat) {
if (stat.isDirectory()) {
dirs.Push(this.file);
}
if (files.length === (this.index + 1)) {
return cb(dirs);
}
}.bind({index: index, file: file}));
}
}
});
}
あるいは、外部ライブラリを使用できる場合は、filehound
を使用できます。それはコールバック、約束と同期呼び出しをサポートします。
約束を使う:
const Filehound = require('filehound');
Filehound.create()
.path("MyFolder")
.directory() // only search for directories
.find()
.then((subdirectories) => {
console.log(subdirectories);
});
コールバックを使う:
const Filehound = require('filehound');
Filehound.create()
.path("MyFolder")
.directory()
.find((err, subdirectories) => {
if (err) return console.error(err);
console.log(subdirectories);
});
同期呼び出し:
const Filehound = require('filehound');
const subdirectories = Filehound.create()
.path("MyFolder")
.directory()
.findSync();
console.log(subdirectories);
詳細情報(および例)については、次のドキュメントを参照してください。 https://github.com/nspragg/filehound
免責事項:私は作者です。
Node.jsバージョン> = v10.13.0では、withFileTypes
オプションがtrue
に設定されている場合、 fs.readdirSync は fs.Dirent オブジェクトの配列を返します。
だから、あなたは使うことができます、
const fs = require('fs')
const directories = source => fs.readdirSync(source, {
withFileTypes: true
}).reduce((a, c) => {
c.isDirectory() && a.Push(c.name)
return a
}, [])
Fs-extraを使用すると、async fs呼び出しと新しいawait async構文が約束されます。
const fs = require("fs-extra");
async function getDirectories(path){
let filesAndDirectories = await fs.readdir(path);
let directories = [];
await Promise.all(
filesAndDirectories.map(name =>{
return fs.stat(path + name)
.then(stat =>{
if(stat.isDirectory()) directories.Push(name)
})
})
);
return directories;
}
let directories = await getDirectories("/")
そしてgetDirectoriesの非同期版では、これには 非同期モジュール が必要です。
var fs = require('fs');
var path = require('path');
var async = require('async'); // https://github.com/caolan/async
// Original function
function getDirsSync(srcpath) {
return fs.readdirSync(srcpath).filter(function(file) {
return fs.statSync(path.join(srcpath, file)).isDirectory();
});
}
function getDirs(srcpath, cb) {
fs.readdir(srcpath, function (err, files) {
if(err) {
console.error(err);
return cb([]);
}
var iterator = function (file, cb) {
fs.stat(path.join(srcpath, file), function (err, stats) {
if(err) {
console.error(err);
return cb(false);
}
cb(stats.isDirectory());
})
}
async.filter(files, iterator, cb);
});
}
この回答では、readdirSync
やstatSync
のようなブロッキング関数は使用しません。それは外部の依存関係を使わず、コールバック地獄の奥深くにはいません。
代わりに、Promisesやasync-await
構文のような最新のJavaScriptの便利さを使います。そして非同期の結果は並列に処理されます。順次ではない -
const { readdir, stat } =
require ("fs") .promises
const { join } =
require ("path")
const dirs = async (path = ".") =>
(await stat (path)) .isDirectory ()
? Promise
.all
( (await readdir (path))
.map (p => dirs (join (path, p)))
)
.then
( results =>
[] .concat (path, ...results)
)
: []
私はサンプルパッケージをインストールしてから、私たちの機能をテストします -
$ npm install ramda
$ node
それがうまくいくのを見てみましょう -
> dirs (".") .then (console.log, console.error)
[ '.'
, 'node_modules'
, 'node_modules/ramda'
, 'node_modules/ramda/dist'
, 'node_modules/ramda/es'
, 'node_modules/ramda/es/internal'
, 'node_modules/ramda/src'
, 'node_modules/ramda/src/internal'
]
一般化されたモジュールParallel
を使うと、dirs
の定義を簡単にすることができます -
const Parallel =
require ("./Parallel")
const dirs = async (path = ".") =>
(await stat (path)) .isDirectory ()
? Parallel (readdir (path))
.flatMap (f => dirs (join (path, f)))
.then (results => [ path, ...results ])
: []
上記で使用されているParallel
モジュールは、同様の問題を解決するために設計された一連の関数から抽出されたパターンです。より詳しい説明は、 関連Q&A をご覧ください。
すべてのasync
バージョンを使用する必要がある場合あなたはこのようなものを持つことができます。
ディレクトリの長さを記録し、すべての非同期統計タスクが終了したかどうかを示すインジケータとして使用します。
非同期統計タスクが終了したら、すべてのファイル統計がチェックされたので、コールバックを呼び出します。
これはNode.jsがシングルスレッドである限りしか機能しません。なぜなら、2つの非同期タスクが同時にカウンタを増やすことはないと想定しているからです。
'use strict';
var fs = require("fs");
var path = require("path");
var basePath = "./";
function result_callback(results) {
results.forEach((obj) => {
console.log("isFile: " + obj.fileName);
console.log("fileName: " + obj.isFile);
});
};
fs.readdir(basePath, (err, files) => {
var results = [];
var total = files.length;
var finished = 0;
files.forEach((fileName) => {
// console.log(fileName);
var fullPath = path.join(basePath, fileName);
fs.stat(fullPath, (err, stat) => {
// this will work because Node.js is single thread
// therefore, the counter will not increment at the same time by two callback
finished++;
if (stat.isFile()) {
results.Push({
fileName: fileName,
isFile: stat.isFile()
});
}
if (finished == total) {
result_callback(results);
}
});
});
});
ご覧のとおり、これは「深さ優先」のアプローチであり、これはコールバック地獄につながる可能性があり、それはまったく「機能的」ではありません。非同期タスクをPromiseオブジェクトにラップすることで、Promiseでこの問題を解決しようとしています。
'use strict';
var fs = require("fs");
var path = require("path");
var basePath = "./";
function result_callback(results) {
results.forEach((obj) => {
console.log("isFile: " + obj.fileName);
console.log("fileName: " + obj.isFile);
});
};
fs.readdir(basePath, (err, files) => {
var results = [];
var total = files.length;
var finished = 0;
var promises = files.map((fileName) => {
// console.log(fileName);
var fullPath = path.join(basePath, fileName);
return new Promise((resolve, reject) => {
// try to replace fullPath wil "aaa", it will reject
fs.stat(fullPath, (err, stat) => {
if (err) {
reject(err);
return;
}
var obj = {
fileName: fileName,
isFile: stat.isFile()
};
resolve(obj);
});
});
});
Promise.all(promises).then((values) => {
console.log("All the promise resolved");
console.log(values);
console.log("Filter out folder: ");
values
.filter((obj) => obj.isFile)
.forEach((obj) => {
console.log(obj.fileName);
});
}, (reason) => {
console.log("Not all the promise resolved");
console.log(reason);
});
});
usefs、pathモジュールでフォルダを取得できます。これは約束を使用します。あなたが塗りつぶしを取得する場合、あなたはisDirectory()をisFile()Nodejs - fs-)に変更できます。 -fs.Stats 。最後に、ファイル '名前'ファイル 'テキスト名などを取得することができます。 Nodejs --- Path
var fs = require("fs"),
path = require("path");
//your <MyFolder> path
var p = "MyFolder"
fs.readdir(p, function (err, files) {
if (err) {
throw err;
}
//this can get all folder and file under <MyFolder>
files.map(function (file) {
//return file or folder path, such as **MyFolder/SomeFile.txt**
return path.join(p, file);
}).filter(function (file) {
//use sync judge method. The file will add next files array if the file is directory, or not.
return fs.statSync(file).isDirectory();
}).forEach(function (files) {
//The files is array, so each. files is the folder name. can handle the folder.
console.log("%s", files);
});
});
CoffeeScript版の この答え 、正しいエラー処理:
fs = require "fs"
{join} = require "path"
async = require "async"
get_subdirs = (root, callback)->
fs.readdir root, (err, files)->
return callback err if err
subdirs = []
async.each files,
(file, callback)->
fs.stat join(root, file), (err, stats)->
return callback err if err
subdirs.Push file if stats.isDirectory()
callback null
(err)->
return callback err if err
callback null, subdirs
に依存します 非同期
あるいは、 これにはモジュールを使ってください (すべてのモジュールがあります。
var getDirectories = (rootdir , cb) => {
fs.readdir(rootdir, (err, files) => {
if(err) throw err ;
var dirs = files.map(filename => path.join(rootdir,filename)).filter( pathname => fs.statSync(pathname).isDirectory());
return cb(dirs);
})
}
getDirectories( myDirectories => console.log(myDirectories));``
ES6を使用した完全非同期バージョンでは、ネイティブパッケージfs.promisesおよびasync/awaitのみがファイル操作を並行して実行します。
const fs = require('fs');
const path = require('path');
async function listDirectories(rootPath) {
const fileNames = await fs.promises.readdir(rootPath);
const filePaths = fileNames.map(fileName => path.join(rootPath, fileName));
const filePathsAndIsDirectoryFlagsPromises = filePaths.map(async filePath => ({path: filePath, isDirectory: (await fs.promises.stat(filePath)).isDirectory()}))
const filePathsAndIsDirectoryFlags = await Promise.all(filePathsAndIsDirectoryFlagsPromises);
return filePathsAndIsDirectoryFlags.filter(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.isDirectory)
.map(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.path);
}
テスト済みで、うまく動作します。
withFileTypes
について教えてくれたMayurに感謝します。私は特定のフォルダのファイルを再帰的に取得するために次のコードを書きました。ディレクトリだけを取得するように簡単に変更できます。
const getFiles = (dir, base = '') => readdirSync(dir, {withFileTypes: true}).reduce((files, file) => {
const filePath = path.join(dir, file.name)
const relativePath = path.join(base, file.name)
if(file.isDirectory()) {
return files.concat(getFiles(filePath, relativePath))
} else if(file.isFile()) {
file.__fullPath = filePath
file.__relateivePath = relativePath
return files.concat(file)
}
}, [])
万が一他の誰かがWeb検索からここに来て、既に彼らの依存関係リストにGruntを持っている場合、これに対する答えは自明になります。これが私の解決策です:
/**
* Return all the subfolders of this path
* @param {String} parentFolderPath - valid folder path
* @param {String} glob ['/*'] - optional glob so you can do recursive if you want
* @returns {String[]} subfolder paths
*/
getSubfolders = (parentFolderPath, glob = '/*') => {
return grunt.file.expand({filter: 'isDirectory'}, parentFolderPath + glob);
}
私は個人的にstat関数をループの外で宣言します。
function getSubDirs(dir, cb) {
fs.readdir(dir, function(err, files) {
var dirs = [],
filePath,
checkDirectory = function(err, stat) {
if(stat.isDirectory()) {
dirs.Push(files[i]);
}
if(i + 1 === l) { // last record
cb(dirs);
}
};
for(var i=0, l=files.length; i<l; i++) {
if(files[i][0] !== '.') { // ignore hidden
filePath = dir+'/'+files[i];
fs.stat(filePath, checkDirectory);
}
}
});
}
JShintはそうでなければ文句を言う、そしてあなたは各ループパスで新しい関数呼び出しを作成しているかもしれない。
非同期/待機バリアント:
async function getFolders(path) {
let result = Array();
let files = await fs.readdir(path);
for (let i = 0; i < files.length; i++) {
var filePath = path + '/' + file;
if (await fs.stat(filePath).isDirectory()) {
result.Push(filePath);
}
}
return result;
}
また、fsの代わりに fs-extra を使用することをお勧めします。
関数型プログラミング
const fs = require('fs')
const path = require('path')
const R = require('ramda')
const getDirectories = pathName => {
const isDirectory = pathName => fs.lstatSync(pathName).isDirectory()
const mapDirectories = pathName => R.map(name => path.join(pathName, name), fs.readdirSync(pathName))
const filterDirectories = listPaths => R.filter(isDirectory, listPaths)
return {
paths:R.pipe(mapDirectories)(pathName),
pathsFiltered: R.pipe(mapDirectories, filterDirectories)(pathName)
}
}