Risposte:
Esiste un modulo per questo chiamato rimraf
( https://npmjs.org/package/rimraf ). Fornisce le stesse funzionalità dirm -Rf
Utilizzo asincrono :
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
Sincronizza utilizzo:
rimraf.sync("/some/directory");
deleteFolderRecursive
nella seguente risposta?
recursive
un'opzione: stackoverflow.com/a/57866165/6269864
Per rimuovere la cartella in modo sincrono
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;
con var curPath = p.join(path, file);
purché tu abbia incluso il modulo path:var p = require("path")
path.join(dirpath, file)
dovrebbe essere migliore dipath + "/" + file
La maggior parte delle persone che usano fs
Node.js preferiscono funzioni simili al "modo Unix" di gestire i file. Sto usando fs-extra per portare tutte le cose interessanti:
fs-extra contiene metodi che non sono inclusi nel pacchetto vanilla Node.js fs. Come mkdir -p, cp -r e rm -rf.
Ancora meglio, fs-extra è un calo in sostituzione di fs nativo. Tutti i metodi in fs non sono modificati e collegati ad esso. Significa che puoi sostituire fs con fs-extra :
// this can be replaced
const fs = require('fs')
// by this
const fs = require('fs-extra')
E quindi puoi rimuovere una cartella in questo modo:
fs.removeSync('/tmp/myFolder');
//or
fs.remove('/tmp/myFolder', callback);
removeSync('/tmp/myFolder')
A partire da Node.js 12.10.0 , fs.rmdirSync
supporta un'opzionerecursive
, quindi puoi finalmente fare:
fs.rmdirSync(dir, { recursive: true });
Dove l' recursive
opzione elimina l'intera directory in modo ricorsivo.
recursive: true
ed elimina le cartelle non vuote senza lamentele.
fs.rmdir(path[, options], callback)
ofs.rmdirSync(path[, options])
fs.rmdir
è sperimentale con stabilità 1. "Stabilità: 1 - Sperimentale. La funzione non è soggetta alle regole di versione semantica. In qualsiasi versione futura. L'uso della funzione non è raccomandato negli ambienti di produzione. "
La mia risposta modificata da @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )
Utilizza path.join per una migliore esperienza multipiattaforma. Quindi, non dimenticare di richiederlo.
var path = require('path');
Anche rinominata funzione in 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);
}
}
Di solito non riesco a resuscitare vecchi thread, ma qui c'è molto da sfornare e senza la risposta del rimraf, questi mi sembrano eccessivamente complicati.
Innanzitutto nel nodo moderno (> = v8.0.0) è possibile semplificare il processo utilizzando solo moduli core del nodo, completamente asincroni, e parallelizzare lo scollegamento dei file contemporaneamente in una funzione di cinque righe e mantenere comunque la leggibilità:
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);
};
In un'altra nota, una guardia per gli attacchi di attraversamento del percorso è inappropriata per questa funzione perché
rm -rf
in quanto accetta un argomento e consentirà all'utente rm -rf /
se richiesto. Sarebbe responsabilità di uno script non proteggere il rm
programma stesso..isDirectory()
è false
per SYM-link e sono scollegati non ricorsivo in.Ultimo ma non meno importante, esiste una rara condizione che la ricorsione potrebbe errori se una delle voci fosse scollegata o eliminata al di fuori di questo script al momento giusto mentre questa ricorsione è in esecuzione. Poiché questo scenario non è tipico nella maggior parte degli ambienti, può essere trascurato. Tuttavia, se necessario (per alcuni casi limite) questo problema può essere mitigato con questo esempio leggermente più complesso:
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: crea isDirectory()
una funzione. Rimuovere la directory effettiva alla fine. Correzione della ricorsione mancante.
await
il proprio Promise.all(…)
; è intenzionale? Sembra che nel suo stato attuale results.forEach
ripeterebbe le promesse, mentre il codice prevede di ripetere i risultati. Mi sto perdendo qualcosa?
if (!fs.existsSync(dir)) return
readdir
genererà un errore come dovrebbe. Se rmdir non-existing-dir
il codice di uscita è un errore. Sarebbe responsabilità del consumatore provare / catturare. Questo è lo stesso metodo descritto nei documenti Node quando si tratta di usare le funzioni fs. Si aspettano che tu provi / catturi e osservi gli errori code
per determinare cosa fare. Un controllo extra introduce una condizione di gara.
fs.exists
viene utilizzata la versione sincrona di . PS questa è un'ottima soluzione.
Ecco una versione asincrona della risposta di @ SharpCoder
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);
});
});
});
};
Ho scritto questa funzione chiamata Rimuovi cartella. Rimuoverà in modo ricorsivo tutti i file e le cartelle in una posizione. L'unico pacchetto richiesto è asincrono.
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)
})
})
})
}
Se stai usando il nodo 8+ vuoi l'asincronicità e non vuoi dipendenze esterne, ecco la versione asincrona / wait:
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);
}
}
Versione asincrona della risposta di @ SharpCoder usando 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);
}
};
Ho raggiunto qui mentre cercavo di andare oltre gulp
e scrivo per ulteriori approfondimenti.
gulp-clean
deprecato per gulp-rimraf
gulp-rimraf
deprecato a favore di delete-files-folders
Quando si desidera eliminare file e cartelle utilizzando del
, è necessario aggiungere /**
per l'eliminazione ricorsiva.
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
Il pacchetto di fatto è rimraf
, ma ecco la mia piccola versione asincrona:
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))
}
Nella versione più recente di Node.js (12.10.0 o successiva), le rmdir
funzioni di stile fs.rmdir()
, fs.rmdirSync()
e fs.promises.rmdir()
hanno una nuova opzione sperimentale recursive
che permette di eliminare le directory non vuote, ad esempio,
fs.rmdir(path, { recursive: true });
Il relativo PR su GitHub: https://github.com/nodejs/node/pull/29168
Secondo la fs
documentazione , fsPromises
attualmente fornisce l' recursive
opzione su base sperimentale, che, almeno nel mio caso su Windows, rimuove la directory e tutti i file in essa contenuti.
fsPromises.rmdir(path, {
recursive: true
})
Rimuove recursive: true
i file su Linux e MacOS?
Ultra-velocità e a prova di guasto
È possibile utilizzare il lignator
pacchetto ( https://www.npmjs.com/package/lignator ), è più veloce di qualsiasi codice asincrono (ad esempio rimraf) e più a prova di errore (specialmente in Windows, dove la rimozione dei file non è istantanea e i file potrebbero essere bloccato da altri processi).
4,36 GB di dati, 28 042 file, 4 217 cartelle su Windows rimosse in 15 secondi contro i 60 secondi di rimraf sul vecchio HDD.
const lignator = require('lignator');
lignator.remove('./build/');
Sincronizza cartella rimossa con i file o solo un file.
Non sono un grande donatore né un collaboratore, ma non sono riuscito a trovare una buona soluzione a questo problema e ho dovuto trovare la mia strada ... quindi spero che ti piaccia :)
Funziona perfettamente per me con qualsiasi numero di directory e sottodirectory nidificate. Attenzione per l'ambito di "questo" quando si ricorre alla funzione, l'implementazione potrebbe essere diversa. Nel mio caso questa funzione rimane nel ritorno di un'altra funzione, ecco perché la chiamo così.
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);
}
Mentre recursive
è un'opzione sperimentale difs.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);
});
});
});
}
Aggiornamento 2020
Dalla versione 12.10.0 recursiveOption è stato aggiunto per le opzioni.
Si noti che la cancellazione ricorsiva è sperimentale .
Quindi faresti per la sincronizzazione:
fs.rmdirSync(dir, {recursive: true});
o per asincrono:
fs.rmdir(dir, {recursive: true});
Basta usare il modulo rmdir ! è facile e semplice.
Un'altra alternativa consiste nell'utilizzare il fs-promise
modulo che fornisce versioni promesse dei fs-extra
moduli
potresti quindi scrivere come in questo esempio:
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)
nota: async / waitit richiede una versione recente di nodejs (7.6+)
Un modo rapido e sporco (forse per il test) potrebbe essere quello di utilizzare direttamente il metodo exec
o spawn
per invocare la chiamata del sistema operativo per rimuovere la directory. Maggiori informazioni su NodeJs child_process .
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
Gli aspetti negativi sono:
Benefici:
-f
flag per sicurezza, o assicurarsi durante la digitazione che non cancellerà tutto. exec + rm
è un comando valido e utile nel nodo che utilizzo spesso durante i test.
Vorrei che ci fosse un modo per farlo senza moduli aggiuntivi per qualcosa di così minuscolo e comune, ma questo è il migliore che ho potuto inventare.
Aggiornamento: ora dovrebbe funzionare su Windows (testato Windows 10) e dovrebbe funzionare anche su sistemi 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
ciò che non invoca la shell e passa invece argomenti in modo esplicito.
Questo è un approccio che utilizza promisify e due funzioni di aiuto (da e verso All) per risolvere la promessa.
Fa tutte le azioni asincrone.
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)
}
};
// senza utilizzo di lib di terze parti
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)
per una matrice di percorsi in una cartella, scorrerefs.unlink(filename)
per eliminare ogni file e infinefs.rmdir(dirPath)
eliminare la cartella ora vuota. Se è necessario ricorrere, controllarefs.lstat(filename).isDirectory()
.