ลบไดเรกทอรีที่ไม่ว่างเปล่า


300

ในแอปพลิเคชั่น Node ของฉันฉันจำเป็นต้องลบไดเรกทอรีที่มีไฟล์บางไฟล์ แต่fs.rmdirใช้ได้เฉพาะกับไดเรกทอรีที่ว่างเปล่า ฉันจะทำสิ่งนี้ได้อย่างไร


1
กล่าวโดยย่อ: fs.readdir(dirPath)สำหรับอาร์เรย์ของพา ธ ในโฟลเดอร์ให้ทำซ้ำfs.unlink(filename)เพื่อลบแต่ละไฟล์จากนั้นจึงfs.rmdir(dirPath)ลบโฟลเดอร์ว่างทันที หากคุณจำเป็นต้อง recurse fs.lstat(filename).isDirectory()ตรวจสอบ
iono

คำตอบ:


319

มีโมดูลสำหรับสิ่งนี้เรียกว่าrimraf( https://npmjs.org/package/rimraf ) มันมีฟังก์ชั่นเดียวกับrm -Rf

การใช้Async :

var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });

การใช้งานการซิงค์ :

rimraf.sync("/some/directory");

1
แปลกฉันไม่เคยเห็นพฤติกรรมแบบนั้น ฉันขอแนะนำให้ค้นหาและ / หรือยื่นข้อผิดพลาด github.com/isaacs/rimraf/issues
มอร์แกน ARR Allen

35
นี่เป็นสิ่งที่สามารถทำได้อย่างง่ายดายด้วย NodeJS Core libs ทำไมจึงต้องติดตั้งแพ็คเกจจากบุคคลที่สาม
SudoKid

4
@EmettSpeer คุณหมายถึง "สามารถทำได้อย่างง่ายดาย" เมื่อใด ฟังก์ชั่นการเขียนตัวเองเหมือนdeleteFolderRecursiveในคำตอบต่อไปนี้?
Freewind

23
"แต่ถึงแม้จะมีฟังก์ชั่นด้านล่างก็ดีขึ้นแล้วเพิ่มแพ็กเกจที่ไม่จำเป็นลงในระบบของคุณ" ฉันไม่เห็นด้วยอย่างยิ่ง คุณกำลังคิดค้นล้อเลื่อนขึ้นใหม่เป็นครั้งที่ 19 โดยไม่ต้องมีเหตุผลอะไรเลยและเสี่ยงต่อการแนะนำข้อบกพร่องหรือช่องโหว่ด้านความปลอดภัยในกระบวนการนี้ อย่างน้อยก็เสียเวลา Inb4 "สิ่งที่ถ้าพวกเขาวางแพคเกจ" ในกรณีที่ไม่น่าเป็นอย่างยิ่งที่แพคเกจจะถูกลบออกจากรีจิสทรี NPM ที่คุณมักจะสามารถแทนที่ด้วยตัวคุณเองแล้ว ไม่มีจุดใดในการพันหัวของคุณก่อนที่คุณจะทำลายมัน
Demonblack

3
ตอนนี้คุณสามารถใช้recursiveตัวเลือก: stackoverflow.com/a/57866165/6269864

245

เพื่อลบโฟลเดอร์พร้อมกัน

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

const deleteFolderRecursive = function(path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach((file, index) => {
      const curPath = Path.join(path, file);
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        deleteFolderRecursive(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};

33
อาจต้องการเพิ่มการตรวจสอบบางอย่างที่คุณจะไม่เรียกใช้โดยไม่ตั้งใจใน '/' ตัวอย่างเช่นการผ่านพา ธ ที่ว่างเปล่าและการพิมพ์ผิดในไฟล์อาจส่งผลให้ curPath เป็นรูต dir
Jake_Howard

10
การนำไปใช้ที่มีประสิทธิภาพยิ่งขึ้น: แทนที่var curPath = path + "/" + file;ด้วยvar curPath = p.join(path, file);หากคุณได้รวมโมดูลพา ธ :var p = require("path")
Andry

9
Windows มี \ slashes ดังนั้นpath.join(dirpath, file)ควรดีกว่าpath + "/" + file
thybzi

5
คุณอาจได้รับ "เกินขนาดสแต็กการโทรสูงสุด" ด้วยรหัสนี้เนื่องจากมีการดำเนินการมากเกินไปในหนึ่งครั้ง @Walf หากคุณเรียกใช้แอปพลิเคชันคอนโซลคุณมี 1 ไคลเอ็นต์ไม่มาก ดังนั้นไม่จำเป็นต้องใช้ async สำหรับแอปคอนโซลในกรณีนี้
Leonid Dashko

4
ฉันได้รับ 'ข้อผิดพลาด: ENOTEMPTY: ไดเรกทอรีไม่ว่างเปล่า'
Seagull

168

คนส่วนใหญ่ที่ใช้fsกับ Node.js ต้องการฟังก์ชั่นใกล้เคียงกับ "วิธี Unix" ของการจัดการกับไฟล์ ฉันใช้fs-extraเพื่อนำสิ่งดีๆมาให้:

fs-extra มีวิธีการที่ไม่รวมอยู่ในแพ็คเกจ fs ของ vanilla Node.js เช่น mkdir -p, cp -r และ rm -rf

ยิ่งไปกว่านั้นFS พิเศษคือการลดลงของ FS ดั้งเดิม วิธีการทั้งหมดใน fs นั้นไม่ได้ทำการแก้ไขและเชื่อมต่อกับมัน หมายความว่าคุณสามารถแทนที่ fs ด้วยfs-extra ได้ :

// this can be replaced
const fs = require('fs')

// by this
const fs = require('fs-extra')

จากนั้นคุณสามารถลบโฟลเดอร์ด้วยวิธีนี้:

fs.removeSync('/tmp/myFolder'); 
//or
fs.remove('/tmp/myFolder', callback);

สำหรับเวอร์ชั่นซิงค์ที่คุณต้องการremoveSync('/tmp/myFolder')
olidem

148

ตั้งแต่ 2019 ...

ในฐานะของNode.js 12.10.0 , fs.rmdirSyncสนับสนุนrecursiveตัวเลือกเพื่อให้คุณจนสามารถทำได้:

fs.rmdirSync(dir, { recursive: true });

ที่recursiveตัวเลือกลบไดเรกทอรีทั้งหมดซ้ำ


5
@anneb นั่นเกิดขึ้นถ้าคุณใช้ Node.js รุ่นเก่ากว่า (<12.10) รุ่นล่าสุดรู้จักตัวเลือกrecursive: trueและลบโฟลเดอร์ที่ไม่ว่างโดยไม่มีการร้องเรียน
GOTO 0

9
การลบแบบเรียกซ้ำยังคงอยู่ในช่วงทดลองของโหนด v13.0.1
ทิม

5
ฟังก์ชั่นเป็นลายเซ็นจริง ๆfs.rmdir(path[, options], callback)หรือfs.rmdirSync(path[, options])
conceptdeluxe

@Tim คุณหมายถึงอะไรโดยการทดลอง
Emerica

2
@Emerica ในเอกสารอย่างเป็นทางการของnode.jsมีการแจ้งเตือนสีส้มขนาดใหญ่ว่าfs.rmdirกำลังทำการทดลองด้วยความเสถียร 1. "Stability: 1 - Experimental คุณลักษณะนี้ไม่อยู่ภายใต้กฎ Semantic Versioning การเปลี่ยนแปลงหรือการลบที่เข้ากันได้แบบไม่ย้อนหลัง การเปิดตัวในอนาคตไม่แนะนำให้ใช้คุณสมบัตินี้ในสภาพแวดล้อมการผลิต "
ทิม

24

คำตอบที่แก้ไขของฉันจาก @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )

ใช้ path.join เพื่อประสบการณ์ข้ามแพลตฟอร์มที่ดียิ่งขึ้น ดังนั้นอย่าลืมที่จะกำหนดมัน

var path = require('path');

เปลี่ยนชื่อฟังก์ชั่นเป็นrimraf;) ด้วย

/**
 * Remove directory recursively
 * @param {string} dir_path
 * @see https://stackoverflow.com/a/42505874/3027390
 */
function rimraf(dir_path) {
    if (fs.existsSync(dir_path)) {
        fs.readdirSync(dir_path).forEach(function(entry) {
            var entry_path = path.join(dir_path, entry);
            if (fs.lstatSync(entry_path).isDirectory()) {
                rimraf(entry_path);
            } else {
                fs.unlinkSync(entry_path);
            }
        });
        fs.rmdirSync(dir_path);
    }
}

17

ฉันมักจะไม่ฟื้นคืนชีพเธรดเก่า ๆ แต่มีจำนวนมากที่ปั่นป่วนที่นี่และ Sans rimraf ตอบคำถามเหล่านี้ดูเหมือนจะซับซ้อนเกินไปสำหรับฉัน

สิ่งแรกใน modern Node (> = v8.0.0) คุณสามารถทำให้กระบวนการง่ายขึ้นโดยใช้เพียงโมดูลหลักของโหนด, แบบอะซิงโครนัสอย่างเต็มที่, และขนานการยกเลิกการเชื่อมโยงของไฟล์พร้อมกันทั้งหมดในฟังก์ชั่นห้าบรรทัด

const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const readdir = promisify(fs.readdir);
const rmdir = promisify(fs.rmdir);
const unlink = promisify(fs.unlink);

exports.rmdirs = async function rmdirs(dir) {
  let entries = await readdir(dir, { withFileTypes: true });
  await Promise.all(entries.map(entry => {
    let fullPath = path.join(dir, entry.name);
    return entry.isDirectory() ? rmdirs(fullPath) : unlink(fullPath);
  }));
  await rmdir(dir);
};

ในอีกหมายเหตุเจ้าหน้าที่รักษาความปลอดภัยสำหรับการโจมตีเส้นทางผ่านที่ไม่เหมาะสมสำหรับฟังก์ชั่นนี้เพราะ

  1. มันอยู่นอกขอบเขตบนพื้นฐานของความโสดความรับผิดชอบต่อหลักการ
  2. ควรจัดการโดยผู้เรียกไม่ใช่ฟังก์ชั่นนี้ นี่คือคล้ายกับบรรทัดคำสั่งrm -rfในการที่มันจะโต้แย้งและจะช่วยให้ผู้ใช้rm -rf /ถ้าถาม มันจะเป็นความรับผิดชอบของสคริปต์เพื่อป้องกันไม่ให้rmโปรแกรมเอง
  3. ฟังก์ชั่นนี้จะไม่สามารถระบุการโจมตีดังกล่าวได้เนื่องจากมันไม่มีกรอบอ้างอิง อีกครั้งที่เป็นความรับผิดชอบของผู้โทรที่จะมีบริบทของความตั้งใจที่จะให้มันเป็นข้อมูลอ้างอิงเพื่อเปรียบเทียบเส้นทางการสำรวจเส้นทาง
  4. Sym การเชื่อมโยงไม่ได้กังวลในฐานะ.isDirectory()เป็นfalseสำหรับ SYM การเชื่อมโยงและมีการยกเลิกการเชื่อมโยงไม่ recursed เข้า

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

exports.rmdirs = async function rmdirs(dir) {
  let entries = await readdir(dir, { withFileTypes: true });
  let results = await Promise.all(entries.map(entry => {
    let fullPath = path.join(dir, entry.name);
    let task = entry.isDirectory() ? rmdirs(fullPath) : unlink(fullPath);
    return task.catch(error => ({ error }));
  }));
  results.forEach(result => {
    // Ignore missing files/directories; bail on other errors
    if (result && result.error.code !== 'ENOENT') throw result.error;
  });
  await rmdir(dir);
};

แก้ไข:สร้างisDirectory()ฟังก์ชั่น ลบไดเรกทอรีที่แท้จริงในตอนท้าย แก้ไขการเรียกซ้ำที่ขาดหายไป


1
นี่เป็นทางออกที่เรียบร้อยจริงๆ คำถามเกี่ยวกับโค้ดตัวอย่างที่สอง: คุณจะไม่เรียกawaitตัวคุณPromise.all(…); มันตั้งใจหรือไม่ ดูเหมือนว่าในสถานะปัจจุบันresults.forEachจะย้ำมากกว่าสัญญาในขณะที่รหัสคาดว่าจะซ้ำมากกว่าผลลัพธ์ ฉันพลาดอะไรไปรึเปล่า?
Anton Strogonoff

@Tony คุณถูกต้องมันเป็นพิมพ์ผิด / ข้อผิดพลาด จับดี!
Sukima

อาจตรวจสอบก่อนเพื่อให้แน่ใจว่ามีไดเรกทอรีอยู่หรือไม่ สิ่งที่ต้องการif (!fs.existsSync(dir)) return
GTPV

@GTPV เพราะเหตุใด สิ่งนี้จะเพิ่มความรับผิดชอบของฟังก์ชันนี้ readdirจะโยนข้อผิดพลาดตามที่ควรจะเป็น หากคุณrmdir non-existing-dirรหัสทางออกเป็นข้อผิดพลาด มันจะเป็นความรับผิดชอบของผู้บริโภคที่จะลอง / จับ นี่เป็นวิธีการเดียวกับที่อธิบายไว้ในเอกสารโหนดเมื่อมันมาถึงการใช้ฟังก์ชั่น fs พวกเขาคาดหวังให้คุณลอง / จับและดูข้อผิดพลาดcodeเพื่อพิจารณาว่าจะทำอย่างไร ตรวจสอบพิเศษแนะนำสภาพการแข่งขัน
Sukima

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

12

นี่คือคำตอบ @ SharpCoder ของ async เวอร์ชัน

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

function deleteFile(dir, file) {
    return new Promise(function (resolve, reject) {
        var filePath = path.join(dir, file);
        fs.lstat(filePath, function (err, stats) {
            if (err) {
                return reject(err);
            }
            if (stats.isDirectory()) {
                resolve(deleteDirectory(filePath));
            } else {
                fs.unlink(filePath, function (err) {
                    if (err) {
                        return reject(err);
                    }
                    resolve();
                });
            }
        });
    });
};

function deleteDirectory(dir) {
    return new Promise(function (resolve, reject) {
        fs.access(dir, function (err) {
            if (err) {
                return reject(err);
            }
            fs.readdir(dir, function (err, files) {
                if (err) {
                    return reject(err);
                }
                Promise.all(files.map(function (file) {
                    return deleteFile(dir, file);
                })).then(function () {
                    fs.rmdir(dir, function (err) {
                        if (err) {
                            return reject(err);
                        }
                        resolve();
                    });
                }).catch(reject);
            });
        });
    });
};

10

ฉันเขียนฟังก์ชันนี้เรียกว่าลบโฟลเดอร์ มันจะลบไฟล์และโฟลเดอร์ทั้งหมดซ้ำ ๆ ในตำแหน่งที่ตั้ง แพ็คเกจเดียวที่ต้องใช้คือ async

var async = require('async');

function removeFolder(location, next) {
    fs.readdir(location, function (err, files) {
        async.each(files, function (file, cb) {
            file = location + '/' + file
            fs.stat(file, function (err, stat) {
                if (err) {
                    return cb(err);
                }
                if (stat.isDirectory()) {
                    removeFolder(file, cb);
                } else {
                    fs.unlink(file, function (err) {
                        if (err) {
                            return cb(err);
                        }
                        return cb();
                    })
                }
            })
        }, function (err) {
            if (err) return next(err)
            fs.rmdir(location, function (err) {
                return next(err)
            })
        })
    })
}

4
จริง ๆ แล้วความคิดคือการไม่เขียนโค้ดของคุณเองถ้ามีคนอื่นเขียนไปแล้ว วิธีที่ดีกว่าคือใช้ rimraf หรือ fs-extra หรือโมดูลโหนดอื่น ๆ เพื่อทำงานให้คุณ
Victor Pudeyev

90
ใช่การเขียนโค้ดของคุณเองนั้นแย่มากเพราะการใช้โมดูลของบุคคลที่สามหลายสิบตัวสำหรับการทำงานที่ไม่สำคัญไม่เคยพิสูจน์ว่ามีข้อเสียในแอปพลิเคชั่นขนาดใหญ่
Eric

8

หากคุณกำลังใช้โหนด 8+ ต้องการ asyncronicity และไม่ต้องการการพึ่งพาจากภายนอกนี่คือเวอร์ชัน async / await:

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

const readdir = util.promisify(fs.readdir);
const lstat = util.promisify(fs.lstat);
const unlink = util.promisify(fs.unlink);
const rmdir = util.promisify(fs.rmdir);

const removeDir = async (dir) => {
    try {
        const files = await readdir(dir);
        await Promise.all(files.map(async (file) => {
            try {
                const p = path.join(dir, file);
                const stat = await lstat(p);
                if (stat.isDirectory()) {
                    await removeDir(p);
                } else {
                    await unlink(p);
                    console.log(`Removed file ${p}`);
                }
            } catch (err) {
                console.error(err);
            }
        }))
        await rmdir(dir);
        console.log(`Removed dir ${dir}`);
    } catch (err) {
      console.error(err);
    }
}

4

คำตอบ @ SharpCoderเวอร์ชัน Async โดยใช้ fs.promises:

const fs = require('fs');
const afs = fs.promises;

const deleteFolderRecursive = async path =>  {
    if (fs.existsSync(path)) {
        for (let entry of await afs.readdir(path)) {
            const curPath = path + "/" + entry;
            if ((await afs.lstat(curPath)).isDirectory())
                await deleteFolderRecursive(curPath);
            else await afs.unlink(curPath);
        }
        await afs.rmdir(path);
    }
};

3

ฉันมาถึงที่นี่ในขณะที่พยายามเอาชนะด้วยgulpและฉันกำลังเขียนเพื่อไปให้ถึงต่อไป

เมื่อคุณต้องการลบไฟล์และโฟลเดอร์ที่ใช้delคุณควรผนวก/**การลบแบบเรียกซ้ำ

gulp.task('clean', function () {
    return del(['some/path/to/delete/**']);
});

2

แพ็คเกจพฤตินัยคือrimraf, แต่นี่เป็น async เล็ก ๆ ของฉัน:

const fs = require('fs')
const path = require('path')
const Q = require('q')

function rmdir (dir) {
  return Q.nfcall(fs.access, dir, fs.constants.W_OK)
    .then(() => {
      return Q.nfcall(fs.readdir, dir)
        .then(files => files.reduce((pre, f) => pre.then(() => {
          var sub = path.join(dir, f)
          return Q.nfcall(fs.lstat, sub).then(stat => {
            if (stat.isDirectory()) return rmdir(sub)
            return Q.nfcall(fs.unlink, sub)
          })
        }), Q()))
    })
    .then(() => Q.nfcall(fs.rmdir, dir))
}

2

ในรุ่นล่าสุดของ Node.js (12.10.0 หรือหลังจากนั้น) ซึ่งเป็นrmdirฟังก์ชั่นสไตล์fs.rmdir(), fs.rmdirSync()และfs.promises.rmdir()มีตัวเลือกการทดลองใหม่recursiveที่ช่วยให้การลบไดเรกทอรีที่ไม่ว่างเปล่าเช่น

fs.rmdir(path, { recursive: true });

PR ที่เกี่ยวข้องบน GitHub: https://github.com/nodejs/node/pull/29168


2

อ้างอิงถึงfsเอกสาร , fsPromisesขณะนี้มีrecursiveตัวเลือกบนพื้นฐานการทดลองซึ่งอย่างน้อยในกรณีของตัวเองบน Windows, เอาไดเรกทอรีและไฟล์ใด ๆ นั้น

fsPromises.rmdir(path, {
  recursive: true
})

ไม่recursive: trueลบไฟล์บน Linux และ MacOS?


1

ความเร็วสูงพิเศษและป้องกันข้อผิดพลาด

คุณสามารถใช้lignatorแพคเกจ ( https://www.npmjs.com/package/lignator ) มันเร็วกว่ารหัส async ใด ๆ (เช่น rimraf) และข้อผิดพลาดอื่น ๆ อีกมากมาย (โดยเฉพาะอย่างยิ่งใน Windows ซึ่งการลบไฟล์ไม่ได้เกิดขึ้นทันทีและไฟล์อาจ ถูกล็อคโดยกระบวนการอื่น ๆ )

ข้อมูล 4,36 GB, 28,042 ไฟล์, 4 217 โฟลเดอร์ใน Windows ถูกลบใน15 วินาทีเทียบกับ rimraf ของ 60 วินาทีใน HDD เก่า

const lignator = require('lignator');

lignator.remove('./build/');

1

ซิงค์โฟลเดอร์ลบด้วยไฟล์หรือไฟล์เท่านั้น

ฉันไม่ได้เป็นผู้ให้หรือผู้สนับสนุน แต่ฉันไม่สามารถหาทางออกที่ดีของปัญหานี้ได้และฉันต้องหาวิธีของฉัน ... ดังนั้นฉันหวังว่าคุณจะชอบ :)

การทำงานที่สมบูรณ์แบบสำหรับฉันด้วยจำนวนใด ๆ ไดเร็กทอรีที่ซ้อนกันและไดเร็กทอรีย่อย ข้อควรระวังสำหรับขอบเขตของ 'this' เมื่อเรียกใช้ฟังก์ชันซ้ำการใช้งานของคุณอาจแตกต่างกัน ในกรณีของฉันฟังก์ชั่นนี้จะอยู่ในการคืนค่าของฟังก์ชันอื่นซึ่งเป็นสาเหตุที่ฉันเรียกมันด้วยสิ่งนี้

    const fs = require('fs');

    deleteFileOrDir(path, pathTemp = false){
            if (fs.existsSync(path)) {
                if (fs.lstatSync(path).isDirectory()) {
                    var files = fs.readdirSync(path);
                    if (!files.length) return fs.rmdirSync(path);
                    for (var file in files) {
                        var currentPath = path + "/" + files[file];
                        if (!fs.existsSync(currentPath)) continue;
                        if (fs.lstatSync(currentPath).isFile()) {
                            fs.unlinkSync(currentPath);
                            continue;
                        }
                        if (fs.lstatSync(currentPath).isDirectory() && !fs.readdirSync(currentPath).length) {
                            fs.rmdirSync(currentPath);
                        } else {
                            this.deleteFileOrDir(currentPath, path);
                        }
                    }
                    this.deleteFileOrDir(path);
                } else {
                    fs.unlinkSync(path);
                }
            }
            if (pathTemp) this.deleteFileOrDir(pathTemp);
        }

1

ในขณะที่recursiveเป็นตัวเลือกการทดลองของfs.rmdir

function rm (path, cb) {
    fs.stat(path, function (err, stats) {
        if (err)
            return cb(err);

        if (stats.isFile())
            return fs.unlink(path, cb);

        fs.rmdir(path, function (err) {
            if (!err || err && err.code != 'ENOTEMPTY') 
                return cb(err);

            fs.readdir(path, function (err, files) {
                if (err)
                    return cb(err);

                let next = i => i == files.length ? 
                    rm(path, cb) : 
                    rm(path + '/' + files[i], err => err ? cb(err) : next(i + 1));

                next(0);
            });
        });
    });
}

1

2563 ปรับปรุง

จากเวอร์ชัน 12.10.0 recursiveOptionมีการเพิ่มสำหรับตัวเลือก

โปรดทราบว่าการลบแบบเรียกซ้ำเป็นการทดลองทดลอง

ดังนั้นคุณจะทำการซิงค์:

fs.rmdirSync(dir, {recursive: true});

หรือสำหรับ async:

fs.rmdir(dir, {recursive: true});

0

เพียงแค่ใช้โมดูล rmdir ! มันง่ายและเรียบง่าย


6
ไม่ใช่ความคิดที่ดีที่จะใช้โมดูลสำหรับโค้ดขนาดเล็กทุกชิ้น หากคุณต้องสร้างข้อตกลงใบอนุญาตเช่นนี้จะสร้างความเจ็บปวดที่แท้จริง
มิยะโกะ

4
คุณต้องเพิ่มตัวอย่างโค้ดเพื่อให้คำตอบของคุณน่าสนใจยิ่งขึ้น
Xeltor

0

อีกทางเลือกหนึ่งคือการใช้fs-promiseโมดูลที่ให้รุ่นที่ได้รับการรับรองของfs-extraโมดูล

จากนั้นคุณสามารถเขียนเช่นนี้:

const { remove, mkdirp, writeFile, readFile } = require('fs-promise')
const { join, dirname } = require('path')

async function createAndRemove() {
  const content = 'Hello World!'
  const root = join(__dirname, 'foo')
  const file = join(root, 'bar', 'baz', 'hello.txt')

  await mkdirp(dirname(file))
  await writeFile(file, content)
  console.log(await readFile(file, 'utf-8'))
  await remove(join(__dirname, 'foo'))
}

createAndRemove().catch(console.error)

หมายเหตุ: async / await ต้องการเวอร์ชั่น nodejs ล่าสุด (7.6+)


0

วิธีที่รวดเร็วและสกปรก(อาจใช้สำหรับการทดสอบ)อาจใช้วิธีexecหรือspawnเรียกการเรียก OS โดยตรงเพื่อลบไดเรกทอรี อ่านเพิ่มเติมเกี่ยวกับNodeJs child_process

let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)

ข้อเสียคือ:

  1. คุณขึ้นอยู่กับระบบปฏิบัติการพื้นฐานนั่นคือวิธีเดียวกันนี้จะทำงานใน unix / linux แต่อาจไม่ได้อยู่ใน windows
  2. คุณไม่สามารถจี้กระบวนการได้ตามเงื่อนไขหรือข้อผิดพลาด คุณเพียงแค่ให้งานกับระบบปฏิบัติการพื้นฐานและรอให้รหัสออกจะถูกส่งกลับ

ประโยชน์ที่ได้รับ:

  1. กระบวนการเหล่านี้สามารถเรียกใช้แบบอะซิงโครนัส
  2. คุณสามารถฟังเอาต์พุต / ข้อผิดพลาดของคำสั่งดังนั้นเอาต์พุตคำสั่งจะไม่สูญหาย หากการดำเนินการไม่เสร็จสมบูรณ์คุณสามารถตรวจสอบรหัสข้อผิดพลาดและลองอีกครั้ง

2
สมบูรณ์แบบสำหรับเมื่อคุณเขียนสคริปต์และไม่ต้องการติดตั้งการอ้างอิงเนื่องจากคุณกำลังจะลบสคริปต์นี้ใน 30 วินาทีหลังจากที่คุณลบไฟล์ทั้งหมดของคุณ !!
งัด

มีวิธีที่จะเลอะและลบระบบไฟล์รูทเสมอ ในกรณีนี้ OP สามารถลบการ-fตั้งค่าสถานะเพื่อความปลอดภัยหรือตรวจสอบให้แน่ใจในขณะที่พิมพ์ว่าเขา / เธอจะไม่ลบทุกอย่าง exec + rmเป็นคำสั่งที่ถูกต้องและมีประโยชน์ในโหนดซึ่งฉันใช้บ่อยในระหว่างการทดสอบ
Rash

0

ฉันหวังว่าจะมีวิธีการทำเช่นนี้โดยไม่มีโมดูลเพิ่มเติมสำหรับบางสิ่งบางอย่างที่เล็กและธรรมดา แต่นี่เป็นสิ่งที่ดีที่สุดที่ฉันสามารถทำได้

อัปเดต: ตอนนี้ควรทำงานบน Windows (ทดสอบ Windows 10) และควรทำงานบนระบบ Linux / Unix / BSD / Mac

const
    execSync = require("child_process").execSync,
    fs = require("fs"),
    os = require("os");

let removeDirCmd, theDir;

removeDirCmd = os.platform() === 'win32' ? "rmdir /s /q " : "rm -rf ";

theDir = __dirname + "/../web-ui/css/";

// WARNING: Do not specify a single file as the windows rmdir command will error.
if (fs.existsSync(theDir)) {
    console.log(' removing the ' + theDir + ' directory.');
    execSync(removeDirCmd + '"' + theDir + '"', function (err) {
        console.log(err);
    });
}

บางที fs-extra's เป็นวิธีที่จะไปถ้าคุณต้องการโมดูลเดียว
b01

3
วิธีนี้เป็นอันตรายอย่างจริงจัง การต่อสตริงของคำสั่งเชลล์โดยเฉพาะอย่างยิ่งโดยไม่ต้องหลบหนีเชิญช่องโหว่การเรียกใช้โค้ดและสิ่งที่คล้ายกัน หากคุณจะใช้ rmdir ให้ใช้child_process.execFileซึ่งไม่ได้เรียกใช้เชลล์และส่งผ่านอาร์กิวเมนต์แทนอย่างชัดเจน
nevyn

@nevyn ฉันจะลองและอัปเดตคำตอบถ้าใช้งานได้
b01

มักจะไม่ต้องการใช้บุคคลที่สาม! ขอบคุณ!
Anton Mitsev

นอกจากนั้นวิธีนี้ค่อนข้างช้า api ของ Nodejs เร็วกว่ามาก
เมอร์สลีย์

0

นี่เป็นวิธีการหนึ่งที่ใช้ promisify และฟังก์ชันความช่วยเหลือสองวิธี (ไปยังและทั้งหมด) เพื่อแก้ไขสัญญา

มันทำทุกอย่างแบบอะซิงโครนัส

const fs = require('fs');
const { promisify } = require('util');
const to = require('./to');
const toAll = require('./toAll');

const readDirAsync = promisify(fs.readdir);
const rmDirAsync = promisify(fs.rmdir);
const unlinkAsync = promisify(fs.unlink);

/**
    * @author Aécio Levy
    * @function removeDirWithFiles
    * @usage: remove dir with files
    * @param {String} path
    */
const removeDirWithFiles = async path => {
    try {
        const file = readDirAsync(path);
        const [error, files] = await to(file);
        if (error) {
            throw new Error(error)
        }
        const arrayUnlink = files.map((fileName) => {
            return unlinkAsync(`${path}/${fileName}`);
        });
        const [errorUnlink, filesUnlink] = await toAll(arrayUnlink);
        if (errorUnlink) {
            throw new Error(errorUnlink);
        }
        const deleteDir = rmDirAsync(path);
        const [errorDelete, result] = await to(deleteDir);
        if (errorDelete) {
            throw new Error(errorDelete);
        }
    } catch (err) {
        console.log(err)
    }
}; 

0

// โดยไม่ใช้ lib อื่น ๆ

const fs = require('fs');
var FOLDER_PATH = "./dirname";
var files = fs.readdirSync(FOLDER_PATH);
files.forEach(element => {
    fs.unlinkSync(FOLDER_PATH + "/" + element);
});
fs.rmdirSync(FOLDER_PATH);

1
สิ่งนี้จะใช้ได้กับสิ่งที่ฉันต้องการ แต่คุณอาจต้องการใช้พา ธ มากกว่าการต่อสแลช:fs.unllinkSync(path.join(FOLDER_PATH, element);
jackofallcode

-1
const fs = require("fs")
const path = require("path")

let _dirloc = '<path_do_the_directory>'

if (fs.existsSync(_dirloc)) {
  fs.readdir(path, (err, files) => {
    if (!err) {
      for (let file of files) {
        // Delete each file
        fs.unlinkSync(path.join(_dirloc, file))
      }
    }
  })
  // After the 'done' of each file delete,
  // Delete the directory itself.
  if (fs.unlinkSync(_dirloc)) {
    console.log('Directory has been deleted!')
  }
}

1
ฉันคิดว่าสิ่งนี้ควรทำงานกับไดเรกทอรีที่ซ้อนกัน
fool4jesus

ใช่ทั้งสำหรับไดเรกทอรีที่ซ้อนกันและไม่ซ้อนกัน
Erisan Olasheni
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.