Réponses:
Il existe un module pour cela appelé rimraf
( https://npmjs.org/package/rimraf ). Il fournit les mêmes fonctionnalités querm -Rf
Utilisation asynchrone :
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
Utilisation de la synchronisation :
rimraf.sync("/some/directory");
deleteFolderRecursive
dans la réponse suivante?
recursive
option: stackoverflow.com/a/57866165/6269864
Pour supprimer un dossier de manière synchrone
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;
par var curPath = p.join(path, file);
le module de chemin d'accès fourni:var p = require("path")
path.join(dirpath, file)
devrait être mieux quepath + "/" + file
La plupart des gens qui utilisent fs
Node.js souhaiteraient des fonctions proches de la "façon Unix" de traiter les fichiers. J'utilise fs-extra pour apporter toutes les choses intéressantes:
fs-extra contient des méthodes qui ne sont pas incluses dans le paquet vanilla Node.js fs. Tels que mkdir -p, cp -r et rm -rf.
Encore mieux, fs-extra est une baisse du remplacement des fs natifs. Toutes les méthodes de fs ne sont pas modifiées et y sont attachées. Cela signifie que vous pouvez remplacer fs par fs-extra :
// this can be replaced
const fs = require('fs')
// by this
const fs = require('fs-extra')
Et puis vous pouvez supprimer un dossier de cette façon:
fs.removeSync('/tmp/myFolder');
//or
fs.remove('/tmp/myFolder', callback);
removeSync('/tmp/myFolder')
Depuis Node.js 12.10.0 , fs.rmdirSync
prend en charge une recursive
option, vous pouvez donc enfin faire:
fs.rmdirSync(dir, { recursive: true });
Où l' recursive
option supprime le répertoire entier de manière récursive.
recursive: true
et supprime les dossiers non vides sans se plaindre.
fs.rmdir(path[, options], callback)
oufs.rmdirSync(path[, options])
fs.rmdir
expérimental avec la stabilité 1. "Stabilité: 1 - Expérimentale. La fonctionnalité n'est pas soumise aux règles de version sémantique. Des modifications ou suppressions non rétrocompatibles peuvent se produire dans n'importe quel version future. L'utilisation de cette fonctionnalité n'est pas recommandée dans les environnements de production. "
Ma réponse modifiée de @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )
Utilise path.join pour une meilleure expérience multiplateforme. Alors, n'oubliez pas de l'exiger.
var path = require('path');
Fonction également renommée en 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);
}
}
Je ne ressuscite pas d'habitude de vieux fils mais il y a beaucoup de choses ici et sans la réponse du rimraf, tout cela me semble trop compliqué.
Tout d'abord dans Node moderne (> = v8.0.0), vous pouvez simplifier le processus en utilisant uniquement des modules de base de nœud, entièrement asynchrones, et paralléliser la dissociation de fichiers simultanément, le tout dans une fonction de cinq lignes, tout en conservant la lisibilité:
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);
};
Par ailleurs, une protection contre les attaques de traversée de chemin n'est pas appropriée pour cette fonction car
rm -rf
dans la mesure où il prend un argument et permettra à l'utilisateur de le rm -rf /
demander. Ce serait la responsabilité d'un script de ne pas garder le rm
programme lui-même..isDirectory()
c'est le cas false
pour les liens sym et sont dissociés et non récurrents.Dernier point mais non le moindre, il existe une condition de concurrence rare que la récursivité puisse générer une erreur si l'une des entrées a été dissociée ou supprimée en dehors de ce script au bon moment pendant l'exécution de cette récursivité. Étant donné que ce scénario n'est pas typique dans la plupart des environnements, il peut probablement être ignoré. Cependant, si nécessaire (pour certains cas marginaux), ce problème peut être atténué avec cet exemple légèrement plus complexe:
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: créer isDirectory()
une fonction. Supprimez le répertoire réel à la fin. Correction de la récursion manquante.
await
à votre Promise.all(…)
; est-ce intentionnel? Il semble que dans son état actuel, results.forEach
il répéterait les promesses, tandis que le code s'attend à répéter les résultats. Suis-je en train de manquer quelque chose?
if (!fs.existsSync(dir)) return
readdir
va lancer une erreur comme il se doit. Si vous rmdir non-existing-dir
le code de sortie est une erreur. Il serait de la responsabilité du consommateur d'essayer / attraper. Il s'agit de la même méthode que celle décrite dans les documents Node pour l'utilisation des fonctions fs. Ils s'attendent à ce que vous essayiez / attrapiez et regardiez les erreurs code
pour déterminer quoi faire. Un contrôle supplémentaire introduit une condition de concurrence.
fs.exists
est utilisée. PS c'est une excellente solution.
Voici une version asynchrone de la réponse de @ 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);
});
});
});
};
J'ai écrit cette fonction appelée supprimer le dossier. Il supprimera récursivement tous les fichiers et dossiers d'un emplacement. Le seul package dont il a besoin est 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)
})
})
})
}
Si vous utilisez le noeud 8+, vous voulez asyncronicité et ne voulez pas de dépendances externes, voici la version asynchrone / 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);
}
}
Version asynchrone de la réponse de @ SharpCoder à l' aide de 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);
}
};
Je suis arrivé ici en essayant d'en finir avec le gulp
et j'écris pour plus de portée.
gulp-clean
déconseillé pour gulp-rimraf
gulp-rimraf
déconseillé au profit de delete-files-folders
Lorsque vous souhaitez supprimer des fichiers et des dossiers à l'aide del
, vous devez ajouter /**
une suppression récursive.
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
Le package de facto l'est rimraf
, mais voici ma petite version asynchrone:
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))
}
Dans la dernière version de Node.js (12.10.0 ou plus tard), les rmdir
fonctions de style fs.rmdir()
, fs.rmdirSync()
et fs.promises.rmdir()
ont une nouvelle option expérimentale recursive
qui permet de supprimer des répertoires non vides, par exemple
fs.rmdir(path, { recursive: true });
Le PR associé sur GitHub: https://github.com/nodejs/node/pull/29168
Selon la fs
documentation , fsPromises
fournit actuellement l' recursive
option à titre expérimental, qui, au moins dans mon cas sous Windows, supprime le répertoire et tous les fichiers qu'il contient.
fsPromises.rmdir(path, {
recursive: true
})
Ne recursive: true
supprimez les fichiers sous Linux et Mac OS?
Ultra-rapide et infaillible
Vous pouvez utiliser le lignator
package ( https://www.npmjs.com/package/lignator ), il est plus rapide que tout code asynchrone (par exemple rimraf) et plus résistant aux défaillances (en particulier dans Windows, où la suppression de fichiers n'est pas instantanée et les fichiers peuvent être verrouillé par d'autres processus).
4,36 Go de données, 28 042 fichiers, 4 217 dossiers sur Windows supprimés en 15 secondes contre 60 secondes de rimraf sur l'ancien disque dur.
const lignator = require('lignator');
lignator.remove('./build/');
Supprimer le dossier de synchronisation avec les fichiers ou uniquement un fichier.
Je ne suis pas un grand donateur ni un contributeur mais je n'ai pas pu trouver une bonne solution à ce problème et j'ai dû trouver mon chemin ... alors j'espère que vous l'aimerez :)
Fonctionne parfaitement pour moi avec n'importe quel nombre de répertoires et sous-répertoires imbriqués. Attention à la portée de «ceci» lors de la récursivité de la fonction, votre implémentation peut être différente. Dans mon cas, cette fonction reste dans le retour d'une autre fonction, c'est pourquoi je l'appelle avec cela.
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);
}
Bien que recursive
soit une option expérimentale defs.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);
});
});
});
}
Mise à jour 2020
Depuis la version 12.10.0 recursiveOption a été ajoutée pour les options.
Notez que la suppression récursive est expérimentale .
Vous feriez donc pour la synchronisation:
fs.rmdirSync(dir, {recursive: true});
ou pour async:
fs.rmdir(dir, {recursive: true});
Utilisez simplement le module rmdir ! c'est facile et simple.
Une autre alternative consiste à utiliser le fs-promise
module qui fournit des versions promises des fs-extra
modules
vous pourriez alors écrire comme cet exemple:
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)
note: async / expect nécessite une version récente de nodejs (7.6+)
Un moyen rapide et sale (peut-être pour les tests) pourrait être d'utiliser directement la méthode exec
ou spawn
pour appeler l'appel du système d'exploitation pour supprimer le répertoire. En savoir plus sur NodeJs child_process .
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
Les inconvénients sont:
Avantages:
-f
drapeau pour être sûr, ou s'assurer en tapant qu'il ne va pas tout supprimer. exec + rm
est une commande valide et utile dans le nœud que j'utilise souvent pendant les tests.
Je souhaite qu'il y ait un moyen de le faire sans modules supplémentaires pour quelque chose d'aussi minuscule et commun, mais c'est le meilleur que j'ai pu trouver.
Mise à jour: Devrait maintenant fonctionner sur Windows (testé Windows 10), et devrait également fonctionner sur les systèmes 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
qui n'invoque pas le shell et passez des arguments explicitement à la place.
Il s'agit d'une approche utilisant promisify et deux fonctions d'aide (to et toAll) pour résoudre la promesse.
Il effectue toutes les actions de manière asynchrone.
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)
}
};
// sans utilisation d'une bibliothèque tierce
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)
pour un tableau de chemins dans un dossier, parcourezfs.unlink(filename)
pour supprimer chaque fichier, puis enfinfs.rmdir(dirPath)
pour supprimer le dossier désormais vide. Si vous avez besoin de rechuter, vérifiezfs.lstat(filename).isDirectory()
.