คุณจะรับรายชื่อของไฟล์ทั้งหมดที่มีอยู่ในไดเรกทอรีใน Node.js ได้อย่างไร?


979

ฉันพยายามรับรายชื่อของไฟล์ทั้งหมดที่มีอยู่ในไดเรกทอรีโดยใช้ Node.js ฉันต้องการเอาต์พุตที่เป็นอาร์เรย์ของชื่อไฟล์ ฉันจะทำสิ่งนี้ได้อย่างไร


9
fs.readdirใช้งานได้ แต่ไม่สามารถใช้รูปแบบชื่อไฟล์ glob ls /tmp/*core*ได้ ตรวจสอบgithub.com/isaacs/node-glob Globs สามารถค้นหาได้ในไดเรกทอรีย่อย
Jess

ชำระเงินreaddir-recursiveโมดูลของ NPM แม้ว่าคุณกำลังมองหาชื่อของไฟล์ในไดเรกทอรีย่อยด้วย
Ethan Davis


1
fs.readdir เป็นโซลูชัน async แบบง่าย - ตัวอย่างที่นี่
drorw

หากยังไม่ได้รับคำตอบโดยใช้ตัววนซ้ำ? ฉันสแกนไฟล์ไปแล้ว 2.5 ล้านไฟล์ ... ฉันไม่ต้องการรับรายการเส้นทาง 2.5m หลังจากผ่านไป 10 นาที
Flavien Volken

คำตอบ:


1342

คุณสามารถใช้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);
});

ความแตกต่างระหว่างสองวิธีคือวิธีแรกคือแบบอะซิงโครนัสดังนั้นคุณต้องเตรียมฟังก์ชันการเรียกกลับที่จะดำเนินการเมื่อกระบวนการอ่านสิ้นสุดลง

อันที่สองคือซิงโครนัสซึ่งจะส่งคืนอาร์เรย์ชื่อไฟล์ แต่จะหยุดการเรียกใช้โค้ดของคุณอีกจนกว่ากระบวนการอ่านจะสิ้นสุดลง


204
หมายเหตุ: readdirยังแสดงให้เห็นชื่อไดเรกทอรี เพื่อกรองเหล่านี้ใช้และfs.stat(path, callback(err, stats)) stats.isDirectory()
Rob W

3
ฉันควรเพิ่มที่น่าจะเป็นไปได้ที่คุณควรไปกับ readdire เพราะคุณไม่ต้องการบล็อก IO ในโหนด
DragonKnight

5
@ user3705055 เว้นแต่ว่าคุณกำลังใช้อึกเพื่ออ่านในไดเรกทอรีของไฟล์ตามลำดับแหล่งที่มาและรวบรวมพวกเขาเป็นปฏิบัติการเดียว
r3wt

3
สำหรับวิธีการสัญญาใหม่ดูคำตอบของฉัน
Evan Carroll

2
@Sancarn คุณต้องการที่จะลองแยกวิเคราะห์ผลลัพธ์ของls? เพียงแค่รอจนกว่าจะมีใครสร้างชื่อไฟล์บางส่วนพร้อมช่องว่างและบรรทัดใหม่ ...
Radon Rosborough

199

IMO วิธีที่สะดวกที่สุดในการทำงานดังกล่าวคือการใช้เครื่องมือglob นี่คือแพคเกจแบบกลมสำหรับ node.js ติดตั้งด้วย

npm install glob

จากนั้นใช้ wild card เพื่อจับคู่ชื่อไฟล์ (ตัวอย่างที่นำมาจากเว็บไซต์ของแพ็คเกจ)

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.
})

5
นี่เป็นทางออกที่ดีที่สุดสำหรับฉันเพราะฉันต้องการระบุประเภทไฟล์ง่ายกว่าการเปรียบเทียบสตริง ขอบคุณ
Pogrindis

ฉันชอบสิ่งนี้เช่นกันเพียงเพราะการโค้งเป็นเกือบทักษะพื้นฐานในโหนด หากคุณต้องการได้ชื่อไฟล์กลับมาให้ส่งผ่านcwdวัตถุตัวเลือกใน
jcollum

1
จะได้ผลลัพธ์จากglobภายนอกได้อย่างไร? เช่น. ฉันต้องการconsole.logผลลัพธ์ แต่ไม่ใช่ภายในglob()?
Lanti

13
@Lanti: glob.sync(pattern, [options])วิธีนี้อาจจะใช้ง่ายกว่าเพราะมันจะคืนค่าอาร์เรย์ของชื่อไฟล์มากกว่าการใช้ callback ข้อมูลเพิ่มเติมที่นี่: github.com/isaacs/node-glob
Glenn Lawrence

1
สำหรับคนอย่างฉันที่กำลังมองหาการติดตั้งแบบใช้ก้อนโดยใช้สัญญาตรวจสอบ globby โดย sindresorhus: github.com/sindresorhus/globby
Nacho Coloma

180

คำตอบข้างต้นไม่ได้ทำการค้นหาแบบเรียกซ้ำในไดเรกทอรี นี่คือสิ่งที่ฉันได้สำหรับการค้นหา recursive (ใช้โหนดเดิน : 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);
});

4
fs.readdirSync ดีกว่าเนทีฟทางเลือกที่สร้างขึ้นเป็นพิเศษสำหรับสิ่งนี้
Eraden

37
fs.readdirSync ไม่ได้เดินเข้าไปในไดเรกทอรีย่อยโชคไม่ดีเว้นแต่คุณยินดีที่จะเขียนกิจวัตรของคุณเองเพื่อทำสิ่งนั้นซึ่งคุณไม่ได้ระบุว่ามีโมดูล npm อยู่แล้วเพื่อแก้ไขปัญหานี้
Ruben Tan

6
นี่คือลิงค์ไปยัง gitub repo เดิน + docs: github.com/coolaj86/node-walk
santiagoIT

OP ไม่ได้ถามว่า API อ่านแบบเรียกซ้ำ ไม่ว่าในกรณีใดคำตอบที่ยอมรับจะให้สิ่งที่สามารถใช้เป็นพื้นฐานสำหรับการอ่านแบบเรียกซ้ำ
Igwe Kalu

นี่คือฟังก์ชั่นที่ยอดเยี่ยม คำถามด่วน: มีวิธีที่รวดเร็วในการเพิกเฉย dirs บางอย่าง? ฉันต้องการละเว้นไดเรกทอรีที่เริ่มต้นด้วย.git
j_d

91

รับไฟล์ในทุกส่วนย่อย

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'))

4
ทำไมif (typeof files_ === 'undefined') files_=[];? คุณต้องการเพียงที่จะทำแทนvar files_ = files_ || []; files_ = files_ || [];
jkutianski

4
คุณลืมที่จะเพิ่มจุดเริ่มต้นของvar fs = require('fs'); getFiles
GFoley83

นี่เป็นวิธีแบบเรียกซ้ำ ไม่รองรับโครงสร้างโฟลเดอร์ที่ลึกมากซึ่งจะส่งผลให้เกิด Stack Overflow
Mathias Lykkegaard Lorenzen

63

นี่เป็นวิธีง่ายๆในการใช้เฉพาะ native fsและpathmodules:

// 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);
        }
    });
}

หรือเวอร์ชัน async (ใช้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"...
});

หรือเวอร์ชัน async:

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

ความแตกต่างคือวิธีที่โหนดบล็อกขณะทำการ IO เนื่องจาก API ข้างต้นเหมือนกันคุณสามารถใช้เวอร์ชัน async เพื่อให้มั่นใจถึงประสิทธิภาพสูงสุด

อย่างไรก็ตามมีข้อดีอย่างหนึ่งคือการใช้เวอร์ชันซิงโครนัส มันง่ายกว่าในการรันโค้ดบางอย่างทันทีที่การเดินเสร็จสิ้นดังเช่นในคำสั่งถัดไปหลังจากการเดิน ด้วยเวอร์ชัน async คุณจะต้องมีวิธีพิเศษในการรู้ว่าเมื่อคุณทำเสร็จแล้ว อาจสร้างแผนที่ของเส้นทางทั้งหมดก่อนจากนั้นจึงแจกแจง สำหรับสคริปต์ build / util แบบง่าย (เทียบกับเว็บเซิร์ฟเวอร์ประสิทธิภาพสูง) คุณสามารถใช้เวอร์ชันซิงค์โดยไม่ทำให้เกิดความเสียหายใด ๆ


1
ควรแทนที่บรรทัดในwalkSyncจากwalk(filePath, callback);เป็นwalkSync(filePath, callback);
MIDE11

3
แต่คุณยังคงใช้ fs.statSync ซึ่งบล็อกในเวอร์ชัน async คุณไม่ควรใช้ fs.stat แทนหรือ
MindlessRanger

วิธีนี้มีประโยชน์จริง ๆ และวิธีนี้จะเรียกซ้ำ ขอบคุณ!
Little Roys

35

ณ โหนด 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


7
จนถึงตอนนี้เป็นคำตอบที่ดีที่สุดที่นี่!
Alex Ivasyuv

2
นี่คือสิ่งที่ผู้คนกำลังค้นหาในปี 2020 - ควร "ตรึง"
Val Redchenko

1
คำตอบที่ดีที่สุด 2020!
Yves Lange

26

ใช้สัญญากับ ES7

ใช้แบบอะซิงโครนัสกับ mz / fs

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 ) }
};

อัปเดตสำหรับรายชื่อซ้ำ

ผู้ใช้บางส่วนได้ระบุปรารถนาที่จะเห็นรายชื่อ recursive (แม้ว่าจะไม่ได้อยู่ในคำถาม) ... 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));

5
fs.walk ถูกลบออกจาก fs-contract เนื่องจากไม่รองรับ fs ( github.com/kevinbeaty/fs-promise/issues/28 )
adnan

20

การอ้างอิง

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มันเป็นแง่ดีเกินไป สำหรับสิ่งที่ร้ายแรงเพิ่มการจัดการข้อผิดพลาด


1
ฉันเพิ่มexcludeDirsอาร์กิวเมนต์อาร์เรย์ด้วย มันเปลี่ยนแปลงได้เพียงพอเพื่อให้คุณควรแก้ไขแทน (ถ้าคุณต้องการ) มิฉะนั้นฉันจะเพิ่มในคำตอบที่แตกต่างกัน gist.github.com/AlecTaylor/f3f221b4fb86b4375650
AT

1
@ AT Nice! คุณควรโพสต์คำตอบของคุณเองเพราะเป็นส่วนเสริมที่มีประโยชน์ มารักษาอันนี้กันเถอะ
หูหนาน Rostomyan

19

รุ่นที่ไม่ใช่แบบเรียกซ้ำ

คุณไม่ได้บอกว่าคุณต้องการที่จะทำซ้ำดังนั้นฉันคิดว่าคุณต้องการลูกโดยตรงของไดเรกทอรี

รหัสตัวอย่าง:

const fs = require('fs');
const path = require('path');

fs.readdirSync('your-directory-path')
  .filter((file) => fs.lstatSync(path.join(folder, file)).isFile());

10

โหลดfs:

const fs = require('fs');

อ่านไฟล์async :

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

อ่านการซิงค์ไฟล์:

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

10

หากมีคนยังคงค้นหาสิ่งนี้ฉันทำสิ่งนี้:

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];
    }, []);

และมันทำงานได้ดีมากสำหรับฉัน


ทำงานได้ดีสำหรับฉันและมันซ้ำ เพียงจำไว้ว่าไวยากรณ์การนำเข้ายังคงอยู่หลังแฟล็กในโหนดคุณอาจต้องใช้วิธีเก่า: const fs = require ('fs');
mjsarfatti

@ Josh มันทำงานเหมือนมีเสน่ห์ อย่างไรก็ตามมีบิตของความยากลำบากที่จะเข้าใจวิธีการ[...files, ...getAllFiles(name)]หรือ[...files, name]งาน คำอธิบายเล็กน้อยจะมีประโยชน์มาก :)
Md Mazedul Islam Khan

1
@MdMazedulIslamKhan การ...ใช้ที่นี่เรียกว่าไวยากรณ์การแพร่กระจาย สิ่งที่มันทำคือนำวัตถุทั้งหมดภายในอาร์เรย์และ 'กระจาย' เข้าไปในอาร์เรย์ใหม่ ในกรณีนี้รายการทั้งหมดภายในfilesอาร์เรย์จะถูกเพิ่มในการส่งคืนพร้อมกับค่าทั้งหมดที่ส่งคืนจากการเรียกซ้ำ คุณสามารถอ้างอิงไวยากรณ์การแพร่กระจายได้ที่นี่: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
T90

8

รับ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();
}

6

ฉันเดาจากคำถามของคุณว่าคุณไม่ต้องการชื่อไดเรกทอรีเพียงไฟล์

ตัวอย่าง:

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


5

นี่คือเวอร์ชันเรียกซ้ำแบบอะซิงโครนัส

    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()
    }

4
เข้าสู่นิสัยของการเพิ่มเครื่องหมายอัฒภาคในตอนท้ายของงบของคุณ คุณไม่สามารถย่อขนาดโค้ดได้ อย่างไรก็ตามขอขอบคุณสำหรับการสนับสนุน async ที่จำเป็นมาก
2867288

2
ฮ่า ๆ ๆ ๆ นั่นไม่ใช่ส่วนหนึ่งของสเป็คเพียงแค่บางคนที่เรียกว่า "standardjs" แบบ linting ที่ต้องการ อัฒภาคเป็นวิธีปฏิบัติที่ดีโดยเฉพาะใน Javascript เพื่อรักษาความชัดเจนของโค้ด มิฉะนั้นคุณและทีมของคุณจะต้องจดจำกฎของการแทรกเครื่องหมายอัฒภาคโดยอัตโนมัติและฉันรู้ว่าอย่างน้อยนักพัฒนา JS โดยเฉลี่ยที่ฉันทำงานไม่ขยัน
2867288

@ user2867288 แต่เนื่องจาก ASI มีอยู่เราจึงสามารถใช้ได้ใช่ไหม ฉันใช้ eslint และ prettier เพื่อจัดรูปแบบรหัสของฉันในการบันทึกเป็นประจำและการแทรกเครื่องหมายอัฒภาคไม่ใช่ปัญหา
douira

5

ใช้วิธีการทั่วไปของ @ 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']));

ฉันมีโฟลเดอร์หลัก: scss และอยู่ข้างในโฟลเดอร์อื่น ๆ : ธีม แต่รายการสุดท้ายให้ไดเรกทอรีทั้งหมดไม่ใช่เฉพาะไดเรกทอรีที่ไม่มีผู้กำกับไม่รวมผู้อำนวยการเกิดอะไรขึ้น
SalahAdDin

ใช้งานได้ดีกับ '.' เท่านั้น ไดเรกทอรีโฟลเดอร์ด้วยไดเรกทอรีที่เหลือไม่ทำงาน
SalahAdDin

5

ออกจากกล่อง

ในกรณีที่คุณต้องการวัตถุที่มีโครงสร้างไดเรกทอรีนอกกรอบฉันขอแนะนำให้คุณตรวจสอบไดเรกทอรีต้นไม้ไดเรกทอรีต้นไม้

ให้บอกว่าคุณมีโครงสร้างนี้:

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");

3

นี่คือ 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
}

1

วิธีนี้จะทำงานและเก็บผลลัพธ์ไว้ในไฟล์ test.txt ซึ่งจะปรากฏในไดเรกทอรีเดียวกัน

  fs.readdirSync(__dirname).forEach(file => {
    fs.appendFileSync("test.txt", file+"\n", function(err){
    })
})

1

ฉันเพิ่งสร้างเครื่องมือสำหรับสิ่งนี้ที่ทำได้เพียงแค่นี้ ... มันดึงข้อมูลไดเรกทอรีแบบอะซิงโครนัสและส่งคืนรายการของรายการ คุณสามารถรับไดเรกทอรีไฟล์หรือทั้งสองอย่างโดยมีโฟลเดอร์เป็นอันดับแรก คุณยังสามารถแบ่งหน้าข้อมูลในกรณีที่คุณไม่ต้องการดึงข้อมูลโฟลเดอร์ทั้งหมด

https://www.npmjs.com/package/fs-browser

นี่คือลิงค์หวังว่าจะช่วยให้ใครบางคน!


0

เพียงแค่หัวขึ้น: หากคุณวางแผนที่จะดำเนินการกับแต่ละไฟล์ในไดเรกทอรีให้ลองvinyl-fs (ซึ่งใช้โดยgulp , ระบบสร้างการสตรีม)


0

ฉันทำโมดูลโหนดเพื่อทำงานนี้โดยอัตโนมัติ: mddir

การใช้

โหนด mddir "../relative/path/"

ในการติดตั้ง: npm install mddir -g

เพื่อสร้าง markdown สำหรับไดเรกทอรีปัจจุบัน: mddir

หากต้องการสร้างสำหรับพา ธ สัมบูรณ์ใด ๆ : mddir / absolute / path

เพื่อสร้างสำหรับเส้นทางสัมพัทธ์: mddir ~ / Documents / any

ไฟล์ md ถูกสร้างขึ้นในไดเรกทอรีทำงานของคุณ

ปัจจุบันละเว้น node_modules และ. git โฟลเดอร์

การแก้ไขปัญหา

หากคุณได้รับข้อผิดพลาด 'node \ r: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว' ปัญหาคือระบบปฏิบัติการของคุณใช้การลงท้ายบรรทัดที่แตกต่างกันและ mddir ไม่สามารถแยกวิเคราะห์ได้โดยที่คุณไม่ต้องกำหนดสไตล์การสิ้นสุดของบรรทัดเป็น Unix โดยปกติจะมีผลกับ Windows แต่ยังมี Linux บางเวอร์ชัน การตั้งค่าการสิ้นสุดบรรทัดเป็นสไตล์ Unix ต้องดำเนินการภายในโฟลเดอร์ bin ส่วนกลาง mddir npm

การแก้ไขจุดสิ้นสุดของบรรทัด

รับพา ธ โฟลเดอร์ถังขยะ npm ด้วย:

npm config get prefix

ซีดีลงในโฟลเดอร์นั้น

ชงติดตั้ง dos2unix

dos2unix lib / node_modules / mddir / src / mddir.js

สิ่งนี้จะแปลงจุดสิ้นสุดบรรทัดเป็น Unix แทนที่จะเป็น Dos

จากนั้นรันตามปกติด้วย: node mddir "../relative/path/"

ตัวอย่างโครงสร้างไฟล์ markdown ที่สร้างขึ้น '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

0

ใช้โมดูล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);
});

-1
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);
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.