Câu trả lời:
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");
deleteFolderRecursive
trong câu trả lời sau đây?
recursive
tùy chọn: stackoverflow.com/a/57866165/6269864
Để 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);
}
};
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")
path.join(dirpath, file)
nên tốt hơnpath + "/" + file
Hầu hết những người sử dụng fs
vớ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);
removeSync('/tmp/myFolder')
Kể từ Node.js 12.10.0 , fs.rmdirSync
hỗ trợ recursive
cá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 đó recursive
tùy chọn xóa toàn bộ thư mục đệ quy.
recursive: true
và xóa các thư mục không trống mà không có khiếu nại.
fs.rmdir(path[, options], callback)
hoặcfs.rmdirSync(path[, options])
fs.rmdir
là 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. "
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);
}
}
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ì
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..isDirectory()
là false
cho 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.
await
cho 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.forEach
sẽ 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?
if (!fs.existsSync(dir)) return
readdir
sẽ ném một lỗi như nó nên. Nếu bạn rmdir non-existing-dir
mã 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.
fs.exists
được sử dụng. PS đây là một giải pháp tuyệt vời.
Đâ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);
});
});
});
};
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)
})
})
})
}
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);
}
}
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);
}
};
Tôi đã đến đây trong khi cố gắng vượt qua gulp
và tôi đang viết để tiếp cận.
gulp-clean
không dùng nữa gulp-rimraf
gulp-rimraf
không được ủng hộ delete-files-folders
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/**']);
});
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))
}
Trong phiên bản mới nhất của Node.js (12.10.0 hoặc mới hơn), các rmdir
chức năng phong cách fs.rmdir()
, fs.rmdirSync()
và fs.promises.rmdir()
có một lựa chọn thử nghiệm mới recursive
mà cho phép xóa các thư mục không rỗng, ví dụ:
fs.rmdir(path, { recursive: true });
Các PR liên quan trên GitHub: https://github.com/nodejs/node/pull/29168
Theo fs
tài liệu , fsPromises
hiện cung cấp recursive
tù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
})
Có recursive: true
xóa các tệp trên Linux và MacOS không?
Siêu tốc độ và không bằng chứng
Bạn có thể sử dụng lignator
gó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/');
Đồ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);
}
Trong khi recursive
là 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);
});
});
});
}
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});
Chỉ cần sử dụng mô-đun rmdir ! nó dễ dàng và đơn giản
Một cách khác là sử dụng fs-promise
mô-đun cung cấp các phiên bản fs-extra
mô-đ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+)
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 exec
hoặc spawn
phươ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à:
Những lợi ích:
-f
cờ để 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 + rm
là 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.
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);
});
}
child_process.execFile
cái không gọi shell và thay vào đó chuyển các đối số một cách rõ ràng.
Đâ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)
}
};
// 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);
fs.unllinkSync(path.join(FOLDER_PATH, element);
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!')
}
}
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ạifs.unlink(filename)
để xóa từng tệp, và cuối cùngfs.rmdir(dirPath)
là xóa thư mục hiện trống. Nếu bạn cần tái diễn, kiểm trafs.lstat(filename).isDirectory()
.