Я пытаюсь получить список имен всех файлов, находящихся в каталоге, с помощью Node.js. Мне нужен вывод, представляющий собой массив имен файлов. Как я могу это сделать?
Как получить список имен всех файлов, находящихся в каталоге в Node.js?
Ответы (25)
Вы можете использовать fs.readdir
или _ 2_. fs
включен в ядро Node.js, поэтому ничего устанавливать не нужно.
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);
});
Разница между двумя методами заключается в том, что первый из них асинхронный, поэтому вы должны предоставить функцию обратного вызова, которая будет выполняться по завершении процесса чтения.
Второй - синхронный, он вернет массив имен файлов, но остановит дальнейшее выполнение вашего кода до завершения процесса чтения.
readdir
также показывает имена каталогов. Чтобы отфильтровать их, используйте fs.stat(path, callback(err, stats))
и _ 3_.
- person Rob W; 03.06.2012
ls
или dir /b/s
для этой работы? Можно было бы подумать, что эти методы будут намного быстрее, чем итерация в Node ...
- person Sancarn; 24.06.2017
ls
? Просто подождите, пока кто-нибудь создаст имена файлов со встроенными пробелами и символами новой строки ...
- person Radon Rosborough; 04.08.2017
ls
не очень хорош для списков файлов. Но find
неплохо справляется :)
- person Sancarn; 04.08.2017
withFileTypes
для функций readdir
и readdirSync
и метода isDirectory()
может использоваться для фильтрации только файлов в каталоге - docs и пример здесь
- person bnp887; 30.01.2019
ИМО, наиболее удобный способ выполнять такие задачи - использовать инструмент glob. Вот пакет glob для node.js. Установить с помощью
npm install glob
Затем используйте подстановочный знак для сопоставления имен файлов (пример взят с веб-сайта)
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.
})
Если вы планируете использовать globby, вот пример для поиска любых файлов xml, находящихся в текущей папке.
import globby = require('globby');
const paths = await globby("**/*.xml");
cwd
в объекте параметров.
- person jcollum; 02.09.2015
glob
вне себя? Например. Я хочу console.log
результаты, но не внутри glob()
?
- person Lanti; 09.02.2016
glob.sync(pattern, [options])
, поскольку он просто возвращает массив имен файлов, а не использует обратный вызов. Дополнительная информация здесь: github.com/isaacs/node-glob
- person Glenn Lawrence; 07.06.2016
Однако приведенный выше ответ не выполняет рекурсивный поиск в каталоге. Вот что я сделал для рекурсивного поиска (используя переход по узлам: 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);
});
.git
- person j_d; 03.05.2016
Получить файлы во всех подкаталогах
const fs=require('fs');
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'))
if (typeof files_ === 'undefined') files_=[];
? вам нужно только var files_ = files_ || [];
вместо files_ = files_ || [];
.
- person jkutianski; 03.12.2014
var fs = require('fs');
в начале getFiles
.
- person GFoley83; 01.07.2015
Вот простое решение, использующее только собственные модули fs
и path
:
// 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);
}
});
}
или асинхронная версия (вместо этого используется fs.readdir
):
// 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);
}
});
});
}
Затем вы просто звоните (для версии с синхронизацией):
walkSync('path/to/root/dir', function(filePath, stat) {
// do something with "filePath"...
});
или асинхронная версия:
walk('path/to/root/dir', function(filePath, stat) {
// do something with "filePath"...
});
Разница в том, как узел блокируется при выполнении ввода-вывода. Учитывая, что приведенный выше API такой же, вы можете просто использовать асинхронную версию для обеспечения максимальной производительности.
Однако у синхронной версии есть одно преимущество. Легче выполнить некоторый код сразу после завершения обхода, как в следующей инструкции после обхода. С асинхронной версией вам понадобится дополнительный способ узнать, когда вы закончите. Возможно, сначала создадим карту всех путей, а затем перечислим их. Для простых сценариев сборки / использования (по сравнению с высокопроизводительными веб-серверами) вы можете использовать синхронизирующую версию без какого-либо ущерба.
walkSync
с walk(filePath, callback);
на walkSync(filePath, callback);
- person MIDE11; 07.02.2016
Начиная с Node v10.10.0, можно использовать новую опцию withFileTypes
для fs.readdir
и fs.readdirSync
в сочетании с функцией dirent.isDirectory()
для фильтрации имен файлов в каталоге. Это выглядит так:
fs.readdirSync('./dirpath', {withFileTypes: true})
.filter(item => !item.isDirectory())
.map(item => item.name)
Возвращенный массив имеет вид:
['file1.txt', 'file2.txt', 'file3.txt']
Документы для класса fs.Dirent
Использование обещаний с ES7
Асинхронное использование с mz / fs
Модуль mz
предоставляет обещанные версии библиотеки основных узлов. Использовать их просто. Сначала установите библиотеку ...
npm install mz
Потом...
const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
.catch(err => console.error(err));
В качестве альтернативы вы можете записать их в асинхронных функциях в ES7:
async function myReaddir () {
try {
const file = await fs.readdir('./myDir/');
}
catch (err) { console.error( err ) }
};
Обновление для рекурсивного листинга
Некоторые пользователи указали, что хотят видеть рекурсивный листинг (хотя не в вопросе) ... Используйте _5 _. Это тонкая оболочка для mz
.
npm install fs-promise;
тогда...
const fs = require('fs-promise');
fs.walk('./myDir').then(
listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
нерекурсивная версия
Вы не говорите, что хотите делать это рекурсивно, поэтому я предполагаю, что вам нужны только прямые дочерние элементы каталога.
Образец кода:
const fs = require('fs');
const path = require('path');
fs.readdirSync('your-directory-path')
.filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
Зависимости.
var fs = require('fs');
var path = require('path');
Определение.
// String -> [String]
function fileList(dir) {
return fs.readdirSync(dir).reduce(function(list, file) {
var name = path.join(dir, file);
var isDir = fs.statSync(name).isDirectory();
return list.concat(isDir ? fileList(name) : [name]);
}, []);
}
Использование.
var DIR = '/usr/local/bin';
// 1. List all files in DIR
fileList(DIR);
// => ['/usr/local/bin/babel', '/usr/local/bin/bower', ...]
// 2. List all file names in DIR
fileList(DIR).map((file) => file.split(path.sep).slice(-1)[0]);
// => ['babel', 'bower', ...]
Обратите внимание, что fileList
слишком оптимистичен. Для чего-нибудь серьезного добавьте немного обработки ошибок.
excludeDirs
. Он меняет его достаточно, так что, возможно, вам стоит отредактировать его вместо этого (если вы этого хотите). В противном случае я добавлю это в другом ответе. gist.github.com/AlecTaylor/f3f221b4fb86b4375650
- person A T; 14.01.2016
Я предполагаю из вашего вопроса, что вам не нужны имена каталогов, а только файлы.
Пример структуры каталогов
animals
├── all.jpg
├── mammals
│ └── cat.jpg
│ └── dog.jpg
└── insects
└── bee.jpg
Walk
функция
Кредиты отправляются Джастину Майеру в эта суть
Если вы хотите просто массив путей к файлам, используйте return_object: false
:
const fs = require('fs').promises;
const path = require('path');
async function walk(dir) {
let files = await fs.readdir(dir);
files = await Promise.all(files.map(async file => {
const filePath = path.join(dir, file);
const stats = await fs.stat(filePath);
if (stats.isDirectory()) return walk(filePath);
else if(stats.isFile()) return filePath;
}));
return files.reduce((all, folderContents) => all.concat(folderContents), []);
}
использование
async function main() {
console.log(await walk('animals'))
}
Выход
[
"/animals/all.jpg",
"/animals/mammals/cat.jpg",
"/animals/mammals/dog.jpg",
"/animals/insects/bee.jpg"
];
files.unshift(dir)
перед последним return
функции async. В любом случае было бы лучше, если бы вы могли создать новый вопрос, так как он может помочь другим людям с той же потребностью и получить лучшую обратную связь. ;-)
- person a.barbieri; 06.04.2021
animals/mammals/name
, и я хочу остановиться на млекопитающих, предоставив некоторую глубину [ "/animals/all.jpg", "/animals/mammals/cat.jpg", "/animals/mammals/dog.jpg", "/animals/insects/bee.jpg" ];
- person Aakash; 08.04.2021
если кто-то все еще ищет это, я делаю это:
import fs from 'fs';
import path from 'path';
const getAllFiles = dir =>
fs.readdirSync(dir).reduce((files, file) => {
const name = path.join(dir, file);
const isDirectory = fs.statSync(name).isDirectory();
return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name];
}, []);
и его работа очень хороша для меня
[...files, ...getAllFiles(name)]
или [...files, name]
. Небольшое объяснение было бы очень полезно :)
- person Md Mazedul Islam Khan; 02.02.2020
...
называется синтаксисом распространения. По сути, он берет все объекты внутри массива и «распределяет» их по новому массиву. В этом случае все записи внутри массива files
добавляются к возврату вместе со всеми значениями, возвращаемыми из рекурсивного вызова. Вы можете сослаться на синтаксис распространения здесь: developer.mozilla .org / en-US / docs / Web / JavaScript / Reference /
- person T90; 06.03.2020
Загрузить fs
:
const fs = require('fs');
Прочитать файлы async:
fs.readdir('./dir', function (err, files) {
// "files" is an Array with files names
});
Прочитать файлы синхронизировать:
var files = fs.readdirSync('./dir');
Получите sorted
имена файлов. Вы можете фильтровать результаты по определенному extension
, например, '.txt'
, '.jpg'
и так далее.
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();
}
Из коробки
Если вам нужен готовый объект со структурой каталогов, я настоятельно рекомендую вам проверить дерево каталогов.
Допустим, у вас есть такая структура:
photos
│ june
│ └── windsurf.jpg
└── january
├── ski.png
└── snowboard.jpg
const dirTree = require("directory-tree");
const tree = dirTree("/path/to/photos");
Вернусь:
{
path: "photos",
name: "photos",
size: 600,
type: "directory",
children: [
{
path: "photos/june",
name: "june",
size: 400,
type: "directory",
children: [
{
path: "photos/june/windsurf.jpg",
name: "windsurf.jpg",
size: 400,
type: "file",
extension: ".jpg"
}
]
},
{
path: "photos/january",
name: "january",
size: 200,
type: "directory",
children: [
{
path: "photos/january/ski.png",
name: "ski.png",
size: 100,
type: "file",
extension: ".png"
},
{
path: "photos/january/snowboard.jpg",
name: "snowboard.jpg",
size: 100,
type: "file",
extension: ".jpg"
}
]
}
]
}
Пользовательский объект
В противном случае, если вы хотите создать объект дерева каталогов с вашими пользовательскими настройками, посмотрите следующий фрагмент. Живой пример виден в этом коды и коды..
// my-script.js
const fs = require("fs");
const path = require("path");
const isDirectory = filePath => fs.statSync(filePath).isDirectory();
const isFile = filePath => fs.statSync(filePath).isFile();
const getDirectoryDetails = filePath => {
const dirs = fs.readdirSync(filePath);
return {
dirs: dirs.filter(name => isDirectory(path.join(filePath, name))),
files: dirs.filter(name => isFile(path.join(filePath, name)))
};
};
const getFilesRecursively = (parentPath, currentFolder) => {
const currentFolderPath = path.join(parentPath, currentFolder);
let currentDirectoryDetails = getDirectoryDetails(currentFolderPath);
const final = {
current_dir: currentFolder,
dirs: currentDirectoryDetails.dirs.map(dir =>
getFilesRecursively(currentFolderPath, dir)
),
files: currentDirectoryDetails.files
};
return final;
};
const getAllFiles = relativePath => {
const fullPath = path.join(__dirname, relativePath);
const parentDirectoryPath = path.dirname(fullPath);
const leafDirectory = path.basename(fullPath);
const allFiles = getFilesRecursively(parentDirectoryPath, leafDirectory);
return allFiles;
};
module.exports = { getAllFiles };
Тогда вы можете просто сделать:
// another-file.js
const { getAllFiles } = require("path/to/my-script");
const allFiles = getAllFiles("/path/to/my-directory");
Вот асинхронная рекурсивная версия.
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()
}
Взял общий подход @ Hunan-Rostomyan, сделал его немного более кратким и добавил excludeDirs
аргумент. Было бы тривиально расширить с помощью includeDirs
, просто следуйте тому же шаблону:
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]);
}, []);
}
Пример использования:
console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
Это TypeScript, необязательно рекурсивный, необязательно с регистрацией ошибок и асинхронным решением. Вы можете указать регулярное выражение для имен файлов, которые хотите найти.
Я использовал fs-extra
, потому что это простое улучшение суперсета на fs
.
import * as FsExtra from 'fs-extra'
/**
* Finds files in the folder that match filePattern, optionally passing back errors .
* If folderDepth isn't specified, only the first level is searched. Otherwise anything up
* to Infinity is supported.
*
* @static
* @param {string} folder The folder to start in.
* @param {string} [filePattern='.*'] A regular expression of the files you want to find.
* @param {(Error[] | undefined)} [errors=undefined]
* @param {number} [folderDepth=0]
* @returns {Promise<string[]>}
* @memberof FileHelper
*/
public static async findFiles(
folder: string,
filePattern: string = '.*',
errors: Error[] | undefined = undefined,
folderDepth: number = 0
): Promise<string[]> {
const results: string[] = []
// Get all files from the folder
let items = await FsExtra.readdir(folder).catch(error => {
if (errors) {
errors.push(error) // Save errors if we wish (e.g. folder perms issues)
}
return results
})
// Go through to the required depth and no further
folderDepth = folderDepth - 1
// Loop through the results, possibly recurse
for (const item of items) {
try {
const fullPath = Path.join(folder, item)
if (
FsExtra.statSync(fullPath).isDirectory() &&
folderDepth > -1)
) {
// Its a folder, recursively get the child folders' files
results.push(
...(await FileHelper.findFiles(fullPath, filePattern, errors, folderDepth))
)
} else {
// Filter by the file name pattern, if there is one
if (filePattern === '.*' || item.search(new RegExp(filePattern, 'i')) > -1) {
results.push(fullPath)
}
}
} catch (error) {
if (errors) {
errors.push(error) // Save errors if we wish
}
}
}
return results
}
Мои 2 цента, если кто-то:
Просто хотите перечислить имена файлов (без каталогов) из локальной подпапки в своем проекте
- ✅ Никаких дополнительных зависимостей
- ✅ 1 функция
- ✅ Нормализовать путь (Unix против Windows)
const fs = require("fs");
const path = require("path");
/**
* @param {string} relativeName "resources/foo/goo"
* @return {string[]}
*/
const listFileNames = (relativeName) => {
try {
const folderPath = path.join(process.cwd(), ...relativeName.split("/"));
return fs
.readdirSync(folderPath, { withFileTypes: true })
.filter((dirent) => dirent.isFile())
.map((dirent) => dirent.name.split(".")[0]);
} catch (err) {
// ...
}
};
README.md
package.json
resources
|-- countries
|-- usa.yaml
|-- japan.yaml
|-- gb.yaml
|-- provinces
|-- .........
listFileNames("resources/countries") #=> ["usa", "japan", "gb"]
path
- это имя вашего импортированного require('path')
, но затем вы повторно определяете const path
внутри функции ... Это действительно сбивает с толку и может привести к ошибкам!
- person mesqueeb; 20.09.2020
Это сработает и сохранит результат в файле test.txt, который будет находиться в том же каталоге.
fs.readdirSync(__dirname).forEach(file => {
fs.appendFileSync("test.txt", file+"\n", function(err){
})
})
Я недавно создал для этого инструмент, который делает именно это ... Он асинхронно извлекает каталог и возвращает список элементов. Вы можете получить каталоги, файлы или и то, и другое, причем папки будут первыми. Вы также можете разбить данные на страницы, если вы не хотите извлекать всю папку.
https://www.npmjs.com/package/fs-browser
Это ссылка, надеюсь, она кому-то поможет!
Я создал модуль узла для автоматизации этой задачи: mddir
использование
узел mddir "../relative/path/"
Для установки: npm install mddir -g
Чтобы сгенерировать уценку для текущего каталога: mddir
Чтобы сгенерировать для любого абсолютного пути: mddir / absolute / path
Чтобы сгенерировать для относительного пути: mddir ~ / Documents / something.
Файл md создается в вашем рабочем каталоге.
В настоящее время игнорирует папки node_modules и .git.
Исправление проблем
Если вы получаете сообщение об ошибке «узел \ r: нет такого файла или каталога», проблема в том, что ваша операционная система использует разные окончания строк, и mddir не может их проанализировать без явной установки стиля окончания строки на Unix. Обычно это влияет на Windows, но также и на некоторые версии Linux. Установка окончаний строк в стиле Unix должна выполняться в глобальной папке bin mddir npm.
Исправлены окончания строк
Получите путь к папке npm bin с помощью:
npm config get prefix
CD в эту папку
варить установить dos2unix
библиотека dos2unix / node_modules / mddir / src / mddir.js
Это преобразует окончания строк в Unix вместо Dos
Затем запустите как обычно: node mddir "../relative/path/".
Пример сгенерированной файловой структуры уценки 'directoryList.md'
|-- .bowerrc
|-- .jshintrc
|-- .jshintrc2
|-- Gruntfile.js
|-- README.md
|-- bower.json
|-- karma.conf.js
|-- package.json
|-- app
|-- app.js
|-- db.js
|-- directoryList.md
|-- index.html
|-- mddir.js
|-- routing.js
|-- server.js
|-- _api
|-- api.groups.js
|-- api.posts.js
|-- api.users.js
|-- api.widgets.js
|-- _components
|-- directives
|-- directives.module.js
|-- vendor
|-- directive.draganddrop.js
|-- helpers
|-- helpers.module.js
|-- proprietary
|-- factory.actionDispatcher.js
|-- services
|-- services.cardTemplates.js
|-- services.cards.js
|-- services.groups.js
|-- services.posts.js
|-- services.users.js
|-- services.widgets.js
|-- _mocks
|-- mocks.groups.js
|-- mocks.posts.js
|-- mocks.users.js
|-- mocks.widgets.js
Используйте модуль npm
list-contents. Он считывает содержимое и вложенное содержимое данного каталога и возвращает список путей к файлам и папкам.
const list = require('list-contents');
list("./dist",(o)=>{
if(o.error) throw o.error;
console.log('Folders: ', o.dirs);
console.log('Files: ', o.files);
});
Обычно я использую: FS-Extra.
const fileNameArray = Fse.readdir('/some/path');
Результат:
[
"b7c8a93c-45b3-4de8-b9b5-a0bf28fb986e.jpg",
"daeb1c5b-809f-4434-8fd9-410140789933.jpg"
]
Если многие из вышеперечисленных вариантов кажутся слишком сложными или нет, то вам нужен другой подход с использованием node -dir - https://github.com/fshost/node-dir
npm install node-dir
Вот простая функция для вывода списка всех файлов .xml, выполняющих поиск в подкаталогах.
import * as nDir from 'node-dir' ;
listXMLs(rootFolderPath) {
let xmlFiles ;
nDir.files(rootFolderPath, function(err, items) {
xmlFiles = items.filter(i => {
return path.extname(i) === '.xml' ;
}) ;
console.log(xmlFiles) ;
});
}
fs.readdir
работает, но не может использовать шаблоны подстановки имен файлов, такие какls /tmp/*core*
. Посетите github.com/isaacs/node-glob. Globs может даже искать в подкаталогах. - person Jess   schedule 02.12.2013readdir-recursive
, хотя, если вы также ищете имена файлов в подкаталогах - person Ethan Davis   schedule 11.06.2016