Xóa thư mục không trống


300

Trong ứng dụng Node của tôi, tôi cần xóa một thư mục có một số tệp, nhưng fs.rmdirchỉ hoạt động trên các thư mục trống. Tôi có thể làm cái này như thế nào?


1
Nói tóm lại: fs.readdir(dirPath)đối với một mảng các đường dẫn trong một thư mục, lặp đi lặp lại fs.unlink(filename)để xóa từng tệp, và cuối cùng fs.rmdir(dirPath)là xóa thư mục hiện trống. Nếu bạn cần tái diễn, kiểm tra fs.lstat(filename).isDirectory().
iono

Câu trả lời:


319

Có một mô-đun cho cái này được gọi là rimraf( https://npmjs.org/package/rimraf ). Nó cung cấp các chức năng tương tự nhưrm -Rf

Async sử dụng:

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

Sử dụng đồng bộ hóa :

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

1
Lạ thật, tôi chưa bao giờ thấy hành vi như thế. Tôi khuyên bạn nên tìm kiếm và / hoặc báo lỗi. github.com/isaacs/rimraf/issues
Morgan ARR Allen

35
Đây là điều có thể được thực hiện dễ dàng với NodeJS Core libs tại sao cài đặt gói bên thứ 3 không rõ ràng?
SudoKid

4
@EmettSpeer Khi nào bạn có nghĩa là "được thực hiện dễ dàng"? Tự viết một chức năng như deleteFolderRecursivetrong câu trả lời sau đây?
Freewind

23
"nhưng ngay cả với chức năng bên dưới tốt hơn thì hãy thêm gói không cần thiết vào hệ thống của bạn." Tôi rất không đồng ý. Bạn đang phát minh lại bánh xe lần thứ 19 triệu hoàn toàn không có lý do nào cả và có nguy cơ đưa ra các lỗi hoặc lỗ hổng bảo mật trong quy trình. Ít nhất đó là một sự lãng phí thời gian. Inb4 "what if they drop the pack": trong trường hợp cực kỳ khó xảy ra là gói bị xóa khỏi sổ đăng ký npm, bạn luôn có thể thay thế nó bằng gói của riêng bạn . Không có điểm nào trong việc băng bó đầu của bạn trước khi bạn phá vỡ nó.
Demonblack

3
bây giờ bạn có thể sử dụng một recursivetùy chọn: stackoverflow.com/a/57866165/6269864

245

Để xóa thư mục đồng bộ

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
Có thể muốn thêm một số kiểm tra mà bạn sẽ không vô tình chạy nó trên '/'. Ví dụ, được thông qua một đường dẫn trống và một lỗi đánh máy trong tệp có thể dẫn đến curPath là thư mục gốc.
Jake_Howard

10
Triển khai mạnh mẽ hơn: thay thế var curPath = path + "/" + file;bằng với var curPath = p.join(path, file);điều kiện bạn đã bao gồm mô-đun đường dẫn:var p = require("path")
Andry

9
Windows có \ slash, vì vậy path.join(dirpath, file)nên tốt hơnpath + "/" + file
thybzi

5
Bạn có thể nhận được "vượt quá kích thước ngăn xếp cuộc gọi tối đa" với mã này do có quá nhiều thao tác trong một lần đánh dấu. @Walf nếu bạn chạy ứng dụng console, bạn có 1 client, không nhiều hơn. Vì vậy, không cần sử dụng async cho ứng dụng bảng điều khiển trong trường hợp này
Leonid Dashko

4
Tôi nhận được 'Lỗi: ENOTEMPTY: thư mục không trống'
Seagull

168

Hầu hết những người sử dụng fsvới Node.js đều muốn các chức năng gần với "cách Unix" xử lý các tệp. Tôi đang sử dụng fs-Extra để mang tất cả những thứ hay ho:

fs-Extra chứa các phương thức không có trong gói fs vanilla Node.js. Chẳng hạn như mkdir -p, cp -r và rm -rf.

Thậm chí tốt hơn, fs-Extra là sự thay thế cho fs bản địa. Tất cả các phương thức trong fs đều không được sửa đổi và đính kèm với nó. Điều đó có nghĩa là bạn có thể thay thế fs bằng fs-Extra :

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

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

Và sau đó bạn có thể xóa một thư mục theo cách này:

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

cho phiên bản đồng bộ hóa bạn cầnremoveSync('/tmp/myFolder')
olidem

148

Tính đến năm 2019 ...

Kể từ Node.js 12.10.0 , fs.rmdirSynchỗ trợ recursivecác tùy chọn, do đó cuối cùng bạn cũng có thể thực hiện:

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

Trong đó recursivetùy chọn xóa toàn bộ thư mục đệ quy.


5
@anneb Điều đó xảy ra nếu bạn đang sử dụng phiên bản cũ hơn của Node.js (<12.10). Phiên bản mới nhất nhận ra tùy chọn recursive: truevà xóa các thư mục không trống mà không có khiếu nại.
GOTO 0

9
Loại bỏ đệ quy vẫn đang thử nghiệm kể từ nút v13.0.1
Tim

5
Chữ ký chức năng thực sự là fs.rmdir(path[, options], callback)hoặcfs.rmdirSync(path[, options])
con805tdeluxe

@Tim bạn có ý gì khi thử nghiệm?
Emerica

2
@Emerica Trong các tài liệu của node.js chính thức có một thông báo lớn màu cam nói fs.rmdirlà thử nghiệm với tính ổn định 1. "Tính ổn định: 1 - Thử nghiệm. Tính năng này không tuân theo quy tắc Phiên bản ngữ nghĩa. Thay đổi hoặc loại bỏ không tương thích ngược Phát hành trong tương lai. Việc sử dụng tính năng này không được khuyến nghị trong môi trường sản xuất. "
Tim

24

Câu trả lời được sửa đổi của tôi từ @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )

Sử dụng path.join để có trải nghiệm đa nền tảng tốt hơn. Vì vậy, đừng quên yêu cầu nó.

var path = require('path');

Cũng đổi tên hàm thành 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

Tôi không thường xuyên hồi sinh các chủ đề cũ nhưng có rất nhiều vấn đề ở đây và câu trả lời rimraf tất cả những điều này dường như quá phức tạp đối với tôi.

Đầu tiên trong Node hiện đại (> = v8.0.0), bạn có thể đơn giản hóa quy trình chỉ sử dụng các mô-đun lõi nút, không đồng bộ hoàn toàn và song song việc hủy liên kết các tệp đồng thời trong một chức năng gồm năm dòng và vẫn giữ được tính dễ đọc:

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

Mặt khác, một người bảo vệ cho các cuộc tấn công ngang qua đường dẫn là không phù hợp cho chức năng này bởi vì

  1. Nó nằm ngoài phạm vi dựa trên Nguyên tắc Trách nhiệm duy nhất .
  2. Nên được xử lý bởi người gọi không phải chức năng này. Điều này gần giống với dòng lệnh rm -rfở chỗ nó cần một đối số và sẽ cho phép người dùng rm -rf /nếu được yêu cầu. Trách nhiệm của một kịch bản là không bảo vệrm chính chương trình.
  3. Hàm này sẽ không thể xác định một cuộc tấn công như vậy vì nó không có khung tham chiếu. Một lần nữa, đó là trách nhiệm của người gọi, người sẽ có bối cảnh của ý định sẽ cung cấp cho nó một tài liệu tham khảo để so sánh đường truyền.
  4. Sym-liên kết không phải là một mối quan tâm như .isDirectory()falsecho sym-liên kết và không được liên kết không recursed vào.

Cuối cùng nhưng không kém phần quan trọng, có một điều kiện cuộc đua hiếm hoi là đệ quy có thể bị lỗi nếu một trong các mục không được liên kết hoặc bị xóa bên ngoài tập lệnh này vào đúng thời điểm trong khi đệ quy này đang chạy. Vì kịch bản này không điển hình trong hầu hết các môi trường nên nó có thể bị bỏ qua. Tuy nhiên, nếu được yêu cầu (đối với một số trường hợp cạnh) vấn đề này có thể được giảm thiểu bằng ví dụ phức tạp hơn một chút này:

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

EDIT: Tạo isDirectory()một chức năng. Xóa thư mục thực tế ở cuối. Sửa lỗi đệ quy bị thiếu.


1
Đây là một giải pháp thực sự gọn gàng. Câu hỏi liên quan đến mẫu mã thứ hai: bạn không gọi awaitcho bạn Promise.all(…); Đây có phải là cố ý? Có vẻ như trong trạng thái hiện tại của nó results.forEachsẽ lặp lại qua các lời hứa, trong khi mã dự kiến ​​sẽ lặp lại qua kết quả. Tui bỏ lỡ điều gì vậy?
Anton Strogonoff

@Tony bạn đúng nó là một lỗi đánh máy / lỗi. Nắm bắt tốt!
Sukima

Có thể kiểm tra trước để đảm bảo rằng thư mục tồn tại? đại loại nhưif (!fs.existsSync(dir)) return
GTPV

@GTPV Vì sao? Điều này làm tăng trách nhiệm của chức năng này. readdirsẽ ném một lỗi như nó nên. Nếu bạn rmdir non-existing-dirmã thoát là một lỗi. Nó sẽ là trách nhiệm của người tiêu dùng để thử / bắt. Đây là phương pháp tương tự được mô tả trong các tài liệu Node khi sử dụng các hàm fs. Họ hy vọng bạn sẽ thử / bắt và xem xét lỗi codeđể xác định việc cần làm. Một kiểm tra thêm giới thiệu một điều kiện cuộc đua.
Sukima

Tôi chắc chắn thấy quan điểm của bạn. Mặc dù theo trực giác, việc cố gắng xóa một thư mục không tồn tại sẽ thành công vì đơn giản là nó sẽ không làm gì cả. Không có điều kiện cuộc đua nếu phiên bản đồng bộ fs.existsđược sử dụng. PS đây là một giải pháp tuyệt vời.
GTPV

12

Đây là phiên bản không đồng bộ của câu trả lời @ SharpCoder's

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

Tôi đã viết chức năng này được gọi là loại bỏ thư mục. Nó sẽ loại bỏ đệ quy tất cả các tệp và thư mục trong một vị trí. Gói duy nhất nó yêu cầu là không đồng bộ.

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
Ý tưởng thực sự là không viết mã của riêng bạn nếu nó đã được viết bởi người khác. Cách tốt hơn để làm điều đó là sử dụng rimraf hoặc fs-Extra hoặc bất kỳ mô-đun nút nào khác, để thực hiện công việc cho bạn.
Victor Pudeyev

90
Vâng, viết mã của riêng bạn là rất tệ, bởi vì sử dụng hàng tá mô-đun của bên thứ 3 cho các hoạt động tương đối tầm thường chưa bao giờ được chứng minh là có bất kỳ nhược điểm nào trong các ứng dụng quy mô lớn.
Eric

8

Nếu bạn đang sử dụng nút 8+ muốn không đồng bộ và không muốn phụ thuộc bên ngoài, thì đây là phiên bản 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

Phiên bản Async của câu trả lời @ SharpCoder's bằng 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

Tôi đã đến đây trong khi cố gắng vượt qua gulpvà tôi đang viết để tiếp cận.

Khi bạn muốn xóa các tập tin và thư mục bằng cách sử dụng del, bạn nên chắp thêm /**để xóa đệ quy.

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

2

Gói de facto là rimraf, nhưng đây là phiên bản async nhỏ bé của tôi:

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

Theo fstài liệu , fsPromiseshiện cung cấp recursivetùy chọn trên cơ sở thử nghiệm, ít nhất là trong trường hợp của riêng tôi trên Windows, sẽ xóa thư mục và mọi tệp trong đó.

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

recursive: truexóa các tệp trên Linux và MacOS không?


1

Siêu tốc độ và không bằng chứng

Bạn có thể sử dụng lignatorgói ( https://www.npmjs.com/package/lignator ), nó nhanh hơn bất kỳ mã async nào (ví dụ rimraf) và nhiều bằng chứng không thành công hơn (đặc biệt là trong Windows, trong đó việc xóa tệp không phải là tức thời và các tệp có thể bị khóa bởi các quá trình khác).

4,36 GB dữ liệu, 28 tệp 042, 4 217 thư mục trên Windows bị xóa trong 15 giây so với 60 giây của rimraf trên ổ cứng cũ.

const lignator = require('lignator');

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

1

Đồng bộ hóa thư mục loại bỏ với các tập tin hoặc chỉ một tập tin.

Tôi không phải là người cho cũng không phải là người đóng góp nhưng tôi không thể tìm ra giải pháp tốt cho vấn đề này và tôi phải tìm ra cách của mình ... vì vậy tôi hy vọng bạn sẽ thích nó :)

Hoạt động hoàn hảo với tôi với bất kỳ số lượng nào thư mục lồng nhau và thư mục phụ. Lưu ý về phạm vi 'cái này' khi đệ quy hàm, việc thực hiện của bạn có thể khác. Trong trường hợp của tôi, hàm này nằm trong sự trở lại của một hàm khác, đó là lý do tại sao tôi gọi nó bằng hàm này.

    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

Trong khi recursivelà một lựa chọn thử nghiệm củafs.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

Cập nhật 2020

Từ phiên bản 12.10.0 đệ quy đã được thêm cho các tùy chọn.

Lưu ý rằng xóa đệ quy là thử nghiệm .

Vì vậy, bạn sẽ làm cho đồng bộ hóa:

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

hoặc không đồng bộ:

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

0

Chỉ cần sử dụng mô-đun rmdir ! nó dễ dàng và đơn giản


6
Không phải lúc nào cũng nên sử dụng một mô-đun cho mỗi đoạn mã nhỏ. Nếu bạn phải tạo một thỏa thuận cấp phép chẳng hạn, điều này tạo ra một nỗi đau thực sự.
Mijago

4
bạn cần thêm một mẫu mã để câu trả lời của bạn trở nên thú vị hơn
Xeltor

0

Một cách khác là sử dụng fs-promisemô-đun cung cấp các phiên bản fs-extramô-đun được hứa hẹn

sau đó bạn có thể viết như ví dụ này:

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)

lưu ý: async / await yêu cầu phiên bản nodejs gần đây (7.6+)


0

Một cách nhanh chóng và bẩn thỉu (có thể để thử nghiệm) có thể là sử dụng trực tiếp exechoặc spawnphương thức để gọi lệnh hệ điều hành để xóa thư mục. Đọc thêm về NodeJs child_ process .

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

Nhược điểm là:

  1. Bạn phụ thuộc vào hệ điều hành cơ bản, tức là cùng một phương thức sẽ chạy trong unix / linux nhưng có thể không có trong windows.
  2. Bạn không thể chiếm quyền điều khiển trong các điều kiện hoặc lỗi. Bạn chỉ cần giao nhiệm vụ cho hệ điều hành cơ bản và chờ mã thoát được trả về.

Những lợi ích:

  1. Các quy trình này có thể chạy không đồng bộ.
  2. Bạn có thể lắng nghe đầu ra / lỗi của lệnh, do đó đầu ra lệnh không bị mất. Nếu thao tác chưa hoàn thành, bạn có thể kiểm tra mã lỗi và thử lại.

2
Hoàn hảo khi bạn viết tập lệnh và không muốn cài đặt phụ thuộc vì bạn sẽ xóa tập lệnh này trong 30 giây sau khi bạn xóa tất cả các tệp của mình !!
Mathias

Luôn có cách để làm rối và xóa hệ thống tập tin gốc. Trong trường hợp này, OP có thể xóa -fcờ để an toàn hoặc đảm bảo trong khi gõ rằng anh ấy / cô ấy sẽ không xóa mọi thứ. exec + rmlà một lệnh hợp lệ và hữu ích trong nút mà tôi thường sử dụng trong quá trình thử nghiệm.
Phát ban

0

Tôi ước có một cách để làm điều này mà không cần các mô-đun bổ sung cho một cái gì đó rất nhỏ và phổ biến, nhưng đây là cách tốt nhất tôi có thể nghĩ ra.

Cập nhật: Bây giờ sẽ hoạt động trên Windows (Windows 10 đã thử nghiệm) và cũng sẽ hoạt động trên các hệ thống 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);
    });
}

Có lẽ fs-Extra là cách để đi nếu bạn muốn một mô-đun duy nhất.
b01

3
Phương pháp này hết sức nguy hiểm. Nối chuỗi của một lệnh shell, đặc biệt là không thoát, mời các lỗ hổng thực thi mã và tương tự. Nếu bạn sẽ sử dụng rmdir, hãy sử dụng child_process.execFilecái không gọi shell và thay vào đó chuyển các đối số một cách rõ ràng.
nevyn

@nevyn Tôi sẽ thử và cập nhật câu trả lời của tôi nếu nó hoạt động.
b01

Luôn luôn không thích sử dụng bên thứ ba! Cảm ơn!
Anton Mitsev

Thêm vào đó, phương pháp này khá chậm. Api bản địa của Nodejs nhanh hơn nhiều.
mersey

0

Đây là một cách tiếp cận bằng cách sử dụng Promisify và hai chức năng trợ giúp (đến và tất cả) để giải quyết lời hứa.

Nó làm tất cả các hành động không đồng nhất.

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

// không sử dụng bất kỳ lib của bên thứ ba

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
Điều này sẽ hoạt động cho những gì tôi cần, nhưng bạn có thể muốn sử dụng đường dẫn thay vì nối dấu gạch chéo: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
Tôi nghĩ rằng một cái gì đó như thế này sẽ làm việc cho các thư mục lồng nhau.
lừa4jesus

Có, cả cho thư mục lồng nhau và thư mục không lồng nhau
Erisan Olasheni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.