Я намагаюся отримати список імен усіх файлів, що знаходяться в каталозі, за допомогою Node.js. Я хочу вихід, який є масивом імен файлів. Як я можу це зробити?
readdir-recursive
модуль NPM, хоча якщо ви шукаєте імена файлів у підкаталогах
Я намагаюся отримати список імен усіх файлів, що знаходяться в каталозі, за допомогою Node.js. Я хочу вихід, який є масивом імен файлів. Як я можу це зробити?
readdir-recursive
модуль NPM, хоча якщо ви шукаєте імена файлів у підкаталогах
Відповіді:
Можна скористатися методами fs.readdir
або fs.readdirSync
.
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))
та stats.isDirectory()
.
ls
? Зачекайте, поки хтось створить якісь імена файлів із вбудованими пробілами та новими рядками…
ІМО найбільш сприятливим способом виконання таких завдань є використання глобального інструменту. Ось глобальний пакет для 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.
})
cwd
опцій.
glob
поза собою? Напр. Я хочу до console.log
результатів, але не всередині glob()
?
glob.sync(pattern, [options])
Метод може бути простішим у використанні, оскільки він просто повертає масив імен файлів, а не використання зворотного дзвінка. Більше інформації тут: github.com/isaacs/node-glob
Відповідь вище не здійснює рекурсивного пошуку в каталозі. Ось що я зробив для рекурсивного пошуку ( з допомогою вузла-гуляє : 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
Отримайте файли у всіх підкаталогах
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_ || [];
.
var fs = require('fs');
на початку getFiles
.
Ось просте рішення з використанням лише рідного 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"...
});
Різниця полягає в тому, як вузол блокується під час виконання IO. Зважаючи на те, що API вище однаковий, ви можете просто використовувати версію async, щоб забезпечити максимальну продуктивність.
Однак є одна перевага використання синхронної версії. Простіше виконати якийсь код, як тільки прогулянка виконана, як у наступному виписці після прогулянки. З версією async вам потрібен додатковий спосіб дізнатися, коли ви закінчите. Можливо, спочатку створіть карту всіх шляхів, а потім перерахуйте їх. Для простих сценаріїв побудови / утиліти (проти високопродуктивних веб-серверів) ви можете використовувати версію синхронізації, не завдаючи шкоди.
walkSync
с walk(filePath, callback);
кwalkSync(filePath, callback);
Станом на 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']
mz
Модуль забезпечує promisified версії бібліотеки ядра вузла. Використовувати їх просто. Спочатку встановіть бібліотеку ...
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 ) }
};
Деякі користувачі вказали бажання переглянути рекурсивний список (хоча це не в питанні) ... Використовувати fs-promise
. Це тонка обгортка навколо 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));
Залежності.
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
Ви не кажете, що хочете робити це рекурсивно, тому я припускаю, що вам потрібні лише прямі діти каталогу.
Приклад коду:
const fs = require('fs');
const path = require('path');
fs.readdirSync('your-directory-path')
.filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
Завантажте fs
:
const fs = require('fs');
Читання файлів асинхронізації :
fs.readdir('./dir', function (err, files) {
// "files" is an Array with files names
});
Читання синхронізації файлів :
var files = fs.readdirSync('./dir');
якщо хтось все ще шукає цього, я роблю це:
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]
працює. Трохи пояснень було б дуже корисно :)
...
Використовуваний тут називається синтаксисом поширення. Що в основному він робить, це забирати всі об’єкти всередині масиву і "розносити" його в новий масив. У цьому випадку всі записи всередині files
масиву додаються до повернення разом із усіма значеннями, поверненими з рекурсивного виклику. Ви можете посилатися на синтаксис поширення тут: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Отримати 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();
}
З вашого питання я припускаю, що ви не хочете імен каталогів, а лише файлів.
Приклад:
animals
├── all.jpg
├── mammals
│ └── cat.jpg
│ └── dog.jpg
└── insects
└── bee.jpg
Якщо ви хочете просто масив файлів, шляхи використовують 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), []);
}
console.log(walk('animals'))
повертає:
[
"/animals/all.jpg",
"/animals/mammals/cat.jpg",
"/animals/mammals/dog.jpg",
"/animals/insects/bee.jpg"
];
Кредити переходять на https://gist.github.com/lovasoa/8691344#gistcomment-2927279
Ось асинхронна рекурсивна версія.
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()
}
Застосував загальний підхід @ Хунана-Ростомяна, зробив його ближчим і більш 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']));
Якщо ви хочете, щоб об'єкт зі структурою каталогу вийшов із коробки, я дуже рекомендую вам перевірити дерево каталогів .
Скажімо, у вас така структура:
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");
Це 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
}
Нещодавно я створив інструмент для цього, який робить саме це ... Він отримує каталог асинхронно і повертає список елементів. Ви можете отримати каталоги, файли або обидва, причому папки будуть першими. Ви також можете застосувати дані на сторінки, якщо ви не хочете отримати всю папку.
https://www.npmjs.com/package/fs-browser
Це посилання, сподіваюся, що це комусь допоможе!
Я зробив модуль вузла для автоматизації цього завдання: mddir
вузол mddir "../relative/path/"
Щоб встановити: npm встановіть mddir -g
Для створення розмітки для поточного каталогу: mddir
Для генерації будь-якого абсолютного шляху: mddir / absolut / path
Для генерації для відносного шляху: mddir ~ / Документи / що завгодно.
Файл md генерується у вашому робочому каталозі.
В даний час ігнорує node_modules та .git папки.
Якщо ви отримаєте помилку "вузол \ r: такого файлу чи каталогу немає", проблема полягає в тому, що ваша операційна система використовує різні закінчення рядків, і mddir не може їх розібрати, не чітко встановивши стиль закінчення рядка в Unix. Зазвичай це стосується Windows, але також і деяких версій Linux. Встановлення закінчень рядків у стилі Unix має виконуватися в глобальній папці бін mddir npm.
Отримайте шлях до папки npm bin за допомогою:
npm config get prefix
CD у цю папку
варити встановити dos2unix
dos2unix lib / node_modules / mddir / src / mddir.js
Це перетворює закінчення рядків в Unix замість Dos
Потім запустіть як звичайно з: node mddir "../relative/path/".
|-- .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
списку-вмісту . Він читає вміст та підміст цього каталогу та повертає список шляхів до файлів та папок.
const list = require('list-contents');
list("./dist",(o)=>{
if(o.error) throw o.error;
console.log('Folders: ', o.dirs);
console.log('Files: ', o.files);
});
function getFilesRecursiveSync(dir, fileList, optionalFilterFunction) {
if (!fileList) {
grunt.log.error("Variable 'fileList' is undefined or NULL.");
return;
}
var files = fs.readdirSync(dir);
for (var i in files) {
if (!files.hasOwnProperty(i)) continue;
var name = dir + '/' + files[i];
if (fs.statSync(name).isDirectory()) {
getFilesRecursiveSync(name, fileList, optionalFilterFunction);
} else {
if (optionalFilterFunction && optionalFilterFunction(name) !== true)
continue;
fileList.push(name);
}
}
}
fs.readdir
працює, але не може використовувати глобальні шаблони імен файлів, якls /tmp/*core*
. Перевірте github.com/isaacs/node-glob . Глобуси можуть навіть шукати в підкаталогах.