Próbuję uzyskać listę nazw wszystkich plików obecnych w katalogu przy użyciu Node.js. Chcę wynik, który jest tablicą nazw plików. W jaki sposób mogę to zrobić?
readdir-recursive
Sprawdź moduł NPM, jeśli szukasz także nazw plików w podkatalogach
Próbuję uzyskać listę nazw wszystkich plików obecnych w katalogu przy użyciu Node.js. Chcę wynik, który jest tablicą nazw plików. W jaki sposób mogę to zrobić?
readdir-recursive
Sprawdź moduł NPM, jeśli szukasz także nazw plików w podkatalogach
Odpowiedzi:
Możesz użyć metod fs.readdir
lub 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);
});
Różnica między tymi dwiema metodami polega na tym, że pierwsza jest asynchroniczna, dlatego musisz zapewnić funkcję zwrotną, która zostanie wykonana po zakończeniu procesu odczytu.
Drugi jest synchroniczny, zwróci tablicę nazw plików, ale zatrzyma dalsze wykonywanie kodu do czasu zakończenia procesu odczytu.
readdir
pokazuje także nazwy katalogów . Aby je przefiltrować, użyj fs.stat(path, callback(err, stats))
i stats.isDirectory()
.
ls
? Poczekaj, aż ktoś utworzy jakieś nazwy plików z osadzonymi spacjami i
IMO najbardziej przekonującym sposobem na wykonanie takich zadań jest użycie narzędzia globalnego . Oto pakiet globalny dla node.js. Zainstaluj za pomocą
npm install glob
Następnie użyj symboli wieloznacznych, aby dopasować nazwy plików (przykład pochodzi ze strony internetowej pakietu)
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
w obiekcie opcji.
glob
poza sobą? Na przykład. Chcę console.log
wyniki, ale nie w środku glob()
?
glob.sync(pattern, [options])
Metoda może być łatwiejsza w użyciu, ponieważ zwraca tablicę nazw plików, a nie oddzwanianie. Więcej informacji tutaj: github.com/isaacs/node-glob
Powyższa odpowiedź nie wykonuje jednak wyszukiwania cyklicznego w katalogu. Oto co zrobiłem dla rekurencyjnego wyszukiwania (za pomocą węzła-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);
});
.git
Pobierz pliki we wszystkich podkatalogach
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_=[];
? musisz tylko zrobić var files_ = files_ || [];
zamiast files_ = files_ || [];
.
var fs = require('fs');
na początku getFiles
.
Oto proste rozwiązanie wykorzystujące tylko natywny fs
i path
moduły:
// 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);
}
});
}
lub wersja asynchroniczna ( fs.readdir
zamiast tego używa ):
// 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);
}
});
});
}
Następnie wystarczy zadzwonić (dla wersji synchronizacji):
walkSync('path/to/root/dir', function(filePath, stat) {
// do something with "filePath"...
});
lub wersja asynchroniczna:
walk('path/to/root/dir', function(filePath, stat) {
// do something with "filePath"...
});
Różnica polega na tym, jak węzły blokują się podczas wykonywania operacji we / wy. Biorąc pod uwagę, że powyższy interfejs API jest taki sam, możesz po prostu użyć wersji asynchronicznej, aby zapewnić maksymalną wydajność.
Jest jednak jedna zaleta korzystania z wersji synchronicznej. Łatwiej jest wykonać jakiś kod zaraz po zakończeniu marszu, jak w następnej instrukcji po marszu. W wersji asynchronicznej potrzebujesz dodatkowego sposobu na sprawdzenie, kiedy skończysz. Być może najpierw utworzysz mapę wszystkich ścieżek, a następnie je wyliczysz. W przypadku prostych skryptów kompilacji / wykorzystania (w porównaniu z wysokowydajnymi serwerami WWW) można użyć wersji synchronizacji bez powodowania żadnych szkód.
walkSync
od walk(filePath, callback);
dowalkSync(filePath, callback);
Począwszy od Node 10.10.0, można używać nowej withFileTypes
opcji dla fs.readdir
i fs.readdirSync
w połączeniu z dirent.isDirectory()
funkcją do filtrowania nazw plików w katalogu. To wygląda tak:
fs.readdirSync('./dirpath', {withFileTypes: true})
.filter(item => !item.isDirectory())
.map(item => item.name)
Zwrócona tablica ma postać:
['file1.txt', 'file2.txt', 'file3.txt']
mz
Moduł zapewnia promisified wersje biblioteki węzła lokalnego. Korzystanie z nich jest proste. Najpierw zainstaluj bibliotekę ...
npm install mz
Następnie...
const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
.catch(err => console.error(err));
Możesz też zapisać je w funkcjach asynchronicznych w ES7:
async function myReaddir () {
try {
const file = await fs.readdir('./myDir/');
}
catch (err) { console.error( err ) }
};
Niektórzy użytkownicy wyrazili chęć zobaczenia listy rekurencyjnej (choć nie w pytaniu) ... Użyj fs-promise
. Wokół jest cienkie opakowanie mz
.
npm install fs-promise;
następnie...
const fs = require('fs-promise');
fs.walk('./myDir').then(
listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
Zależności
var fs = require('fs');
var path = require('path');
Definicja.
// 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]);
}, []);
}
Stosowanie.
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', ...]
Pamiętaj, że fileList
jest to zbyt optymistyczne. W przypadku czegoś poważnego dodaj obsługę błędów.
excludeDirs
również argument tablicowy. Zmienia to na tyle, że może powinieneś go edytować (jeśli chcesz). W przeciwnym razie dodam to w innej odpowiedzi. gist.github.com/AlecTaylor/f3f221b4fb86b4375650
Nie mówisz, że chcesz to robić rekurencyjnie, więc zakładam, że potrzebujesz tylko bezpośrednich potomków katalogu.
Przykładowy kod:
const fs = require('fs');
const path = require('path');
fs.readdirSync('your-directory-path')
.filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
Obciążenie fs
:
const fs = require('fs');
Czytaj pliki asynchronicznie :
fs.readdir('./dir', function (err, files) {
// "files" is an Array with files names
});
Czytaj synchronizację plików :
var files = fs.readdirSync('./dir');
jeśli ktoś nadal tego szuka, robię to:
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];
}, []);
i jego praca jest dla mnie bardzo dobra
[...files, ...getAllFiles(name)]
lub [...files, name]
. Trochę wyjaśnienia byłoby bardzo pomocne :)
...
tutaj nazwa nazywa się składnią rozszerzoną. Zasadniczo zajmuje wszystkie obiekty wewnątrz tablicy i „przenosi” ją do nowej tablicy. W takim przypadku wszystkie wpisy w files
tablicy są dodawane do zwrotu wraz ze wszystkimi wartościami zwracanymi z wywołania rekurencyjnego. Możesz zapoznać się ze składnią rozprzestrzeniania tutaj: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Uzyskaj sorted
nazwy plików. Można filtrować wyniki na podstawie konkretnych extension
, takich jak '.txt'
, '.jpg'
i tak dalej.
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();
}
Z twojego pytania zakładam, że nie chcesz nazw katalogów, tylko pliki.
Przykład:
animals
├── all.jpg
├── mammals
│ └── cat.jpg
│ └── dog.jpg
└── insects
└── bee.jpg
Jeśli chcesz tylko tablicę ścieżek plików, użyj 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'))
zwroty:
[
"/animals/all.jpg",
"/animals/mammals/cat.jpg",
"/animals/mammals/dog.jpg",
"/animals/insects/bee.jpg"
];
Kredyty trafiają na https://gist.github.com/lovasoa/8691344#gistcomment-2927279
Oto asynchroniczna wersja rekurencyjna.
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()
}
Przyjęła ogólne podejście @ Hunan-Rostomyan, uczyniła go nieco bardziej zwięzłym i dodała excludeDirs
argument. Rozszerzanie byłoby trywialne includeDirs
, wystarczy postępować według tego samego wzoru:
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]);
}, []);
}
Przykładowe użycie:
console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
Jeśli chcesz mieć obiekt ze strukturą katalogów od razu po wyjęciu z pudełka, gorąco polecam sprawdzenie drzewa katalogów .
Powiedzmy, że masz tę strukturę:
photos
│ june
│ └── windsurf.jpg
└── january
├── ski.png
└── snowboard.jpg
const dirTree = require("directory-tree");
const tree = dirTree("/path/to/photos");
Wróci:
{
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"
}
]
}
]
}
W przeciwnym razie, jeśli chcesz utworzyć obiekt drzewa katalogów z własnymi ustawieniami niestandardowymi, zapoznaj się z poniższym fragmentem. Przykład na żywo jest widoczny na tym kodzie i skrzynce .
// 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 };
Następnie możesz po prostu zrobić:
// another-file.js
const { getAllFiles } = require("path/to/my-script");
const allFiles = getAllFiles("/path/to/my-directory");
Jest to TypeScript, opcjonalnie rekurencyjny, opcjonalnie rejestrowanie błędów i rozwiązanie asynchroniczne. Możesz określić wyrażenie regularne dla nazw plików, które chcesz znaleźć.
Użyłem fs-extra
, ponieważ jest to łatwa, super-poprawka na 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
}
Niedawno zbudowałem do tego narzędzie, które właśnie to robi ... Pobiera katalog asynchronicznie i zwraca listę elementów. Możesz pobrać katalogi, pliki lub oba, z pierwszymi folderami. Możesz także paginować dane w przypadku, gdy nie chcesz pobierać całego folderu.
https://www.npmjs.com/package/fs-browser
To jest link, mam nadzieję, że komuś pomoże!
Zrobiłem moduł węzła, aby zautomatyzować to zadanie: mddir
węzeł mddir „../relative/path/”
Aby zainstalować: npm install mddir -g
Aby wygenerować przecenę dla bieżącego katalogu: mddir
Aby wygenerować dla dowolnej ścieżki bezwzględnej: mddir / absolut / ścieżka
Aby wygenerować dla ścieżki względnej: mddir ~ / Documents /okolwiek.
Plik md zostanie wygenerowany w katalogu roboczym.
Obecnie ignoruje moduły node_modules i .git.
Jeśli pojawi się błąd „node \ r: Brak takiego pliku lub katalogu”, problem polega na tym, że twój system operacyjny używa różnych zakończeń linii i mddir nie może ich przetworzyć bez wyraźnego ustawienia stylu zakończenia linii na Unix. Zwykle dotyczy to systemu Windows, ale także niektórych wersji systemu Linux. Ustawienie zakończenia linii na styl uniksowy należy wykonać w globalnym folderze bin mddir npm.
Uzyskaj ścieżkę folderu bin npm za pomocą:
npm config get prefix
Cd do tego folderu
napar zainstaluj dos2unix
dos2unix lib / node_modules / mddir / src / mddir.js
Konwertuje to zakończenia linii na Unix zamiast Dos
Następnie uruchom normalnie z: 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
Użyj modułu npm
zawartości listy . Odczytuje zawartość i podkatalogi danego katalogu i zwraca listę ścieżek plików i folderów.
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
działa, ale nie może używać wzorców globów nazw plików, takich jakls /tmp/*core*
. Sprawdź github.com/isaacs/node-glob . Globusy mogą nawet wyszukiwać w podkatalogach.