비어 있지 않은 디렉토리를 제거하십시오.
내 노드 응용 프로그램에서 일부 파일이있는 디렉토리를 제거해야하지만 fs.rmdir
빈 디렉토리에서만 작동합니다. 어떻게해야합니까?
이를위한 모듈이 있습니다 rimraf
( https://npmjs.org/package/rimraf ). 그것은 같은 기능을 제공합니다rm -Rf
비동기 사용법 :
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
사용법 동기화 :
rimraf.sync("/some/directory");
폴더를 동 기적으로 제거하려면
var fs = require('fs');
var deleteFolderRecursive = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function(file, index){
var curPath = path + "/" + file;
if (fs.lstatSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
fs
Node.js를 사용 하는 대부분의 사람들 은 파일을 다루는 "유닉스 방식"에 가까운 함수를 원합니다. fs-extra 를 사용하여 모든 멋진 물건을 가져 왔습니다.
fs-extra는 vanilla Node.js fs 패키지에 포함되지 않은 메소드를 포함합니다. mkdir -p, cp -r 및 rm -rf와 같은.
더 좋은 점은 fs-extra 가 기본 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);
@oconnecp ( https : //.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);
}
}
@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);
});
});
});
};
폴더 제거라는이 기능을 작성했습니다. 특정 위치의 모든 파일과 폴더를 재귀 적으로 제거합니다. 필요한 유일한 패키지는 비동기입니다.
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)
})
})
})
}
나는 보통 오래된 실을 부활시키지 않지만 여기에 많은 이탈이 있으며 rimraf 대답은 이것들 모두에게 너무 복잡해 보인다.
현대 노드 (> = v8.0.0)에서 첫 번째로 노드 코어 모듈 만 사용하여 프로세스를 단순화하고 완전히 비 동기화하며 파일의 링크를 동시에 5 줄의 함수로 동시에 병렬화하고 가독성을 유지할 수 있습니다.
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);
};
또 다른 참고로, 경로 순회 공격에 대한 보호 는이 기능에 부적합합니다.
- 단일 책임 원칙 (Single Responsibility Principle) 에 따라 범위를 벗어납니다 .
- 이 함수가 아닌 호출자가 처리해야합니다 . 이것은 명령 행과 유사
rm -rf
하며 인수를 취하고 사용자가rm -rf /
요청하면 이를 허용합니다 .rm
프로그램 자체 를 보호하지 않는 것은 스크립트의 책임입니다 . - 이 기능은 참조 프레임이 없기 때문에 이러한 공격을 확인할 수 없습니다. 또한 경로 통과를 비교하기위한 참조를 제공하려는 의도의 컨텍스트를 갖는 호출자의 책임입니다.
- sym-links
.isDirectory()
는false
sym-links와 마찬가지로 문제 가되지 않으며 연결되지 않은 상태로 되풀이되지 않습니다.
마지막 으로,이 재귀가 실행되는 동안 적절한 시점에 항목 중 하나 가이 스크립트 외부 에서 연결 해제되거나 삭제 된 경우 재귀 오류가 발생할 수있는 드문 경쟁 조건 이 있습니다. 이 시나리오는 대부분의 환경에서 일반적이지 않으므로 간과 될 수 있습니다. 그러나 필요한 경우 (일부 사례의 경우)이 좀 더 복잡한 예제를 통해이 문제를 완화 할 수 있습니다.
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()
기능을 만듭니다 . 마지막에 실제 디렉토리를 제거하십시오. 누락 된 재귀를 수정하십시오.
2019 년 기준 ...
Node.js 12.10을 사용하면 마지막으로 간단하게 할 수 있습니다.
fs.rmdir(dir, { recursive: true });
이 recursive
옵션은 모든 것을 재귀 적으로 삭제합니다.
노드 8 이상을 사용하고 비동기 성을 원하고 외부 종속성을 원하지 않는 경우 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);
}
}
fs.promises를 사용한 @SharpCoder 의 비동기 버전 :
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);
}
};
나는 극복하려고 노력하면서 여기에 도달했으며 gulp
더 많은 도달을 위해 글을 쓰고 있습니다.
gulp-clean
더 이상 사용되지 않습니다gulp-rimraf
gulp-rimraf
더 이상 사용되지 않음delete-files-folders
을 사용하여 파일 및 폴더를 삭제하려면 재귀 삭제를 del
추가해야합니다 /**
.
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
Node.js를 최신 버전 (나중에 12.10.0 이상)에서 rmdir
스타일 기능 fs.rmdir()
, fs.rmdirSync()
그리고 fs.promises.rmdir()
새로운 실험 옵션이 recursive
비어 있지 않은 디렉토리를 삭제 허용, 예를
fs.rmdir(path, { recursive: true });
GitHub 관련 PR : https://github.com/nodejs/node/pull/29168
나는 너무나 사소하고 일반적인 것을 위해 추가 모듈없이 이것을 할 수있는 방법이 있었으면 좋겠다. 그러나 이것이 내가 생각해 낼 수있는 최선이다.
업데이트 : 이제 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);
});
}
동기화 폴더는 파일 또는 파일로만 제거하십시오.
난 안 많이주는 사람이나 기여자의 모르지만, 나는이 문제의 좋은 해결책을 찾을 수 없습니다 나는 당신이 그것을 :) 좋아 바랍니다 그래서 나는 ... 내 길을 찾아야했다
임의의 수와 나를 위해 작동 완벽 중첩 된 디렉토리 및 하위 디렉토리. 함수를 되풀이 할 때 '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);
}
사실상의 패키지는 rimraf
이지만 여기에 작은 비동기 버전이 있습니다.
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))
}
그냥 rmdir 모듈을 사용하십시오 ! 쉽고 간단합니다.
또 다른 대안은 사용 fs-promise
의 promisified 버전 제공 모듈 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 이상)이 필요합니다
빠르고 테스트하는 방법 은 테스트 를 위해 직접 exec
또는 spawn
메소드를 사용 하여 디렉토리를 제거하기 위해 OS 호출을 호출하는 것입니다. NodeJs child_process 에 대해 자세히 알아보십시오 .
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
단점은 다음과 같습니다.
- 기본 OS에 의존하고 있습니다. 즉, 동일한 방법이 unix / linux에서 실행되지만 아마도 Windows에서는 실행되지 않습니다.
- 조건이나 오류로 프로세스를 가로 챌 수 없습니다. 태스크를 기본 OS에 제공하고 종료 코드가 리턴 될 때까지 기다리십시오.
혜택:
- 이러한 프로세스는 비동기 적으로 실행될 수 있습니다.
- 명령의 출력 / 오류를들을 수 있으므로 명령 출력이 손실되지 않습니다. 작업이 완료되지 않으면 오류 코드를 확인하고 다시 시도 할 수 있습니다.
이것은 약속을 해결하기 위해 약속과 두 가지 도움말 기능을 사용하는 하나의 접근 방식입니다.
모든 작업을 비동기 적으로 수행합니다.
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)
}
};
초고속 및 고장 방지
lignator
패키지 ( https://www.npmjs.com/package/lignator )를 사용할 수 있으며 비동기 코드 (예 : rimraf)보다 빠르며 고장 방지 (특히 Windows에서 파일 제거가 즉각적이지 않고 파일이있을 수 있음) 다른 프로세스에 의해 잠김).
Windows에서 4,36GB의 데이터, 28 042 개의 파일, 4217 개의 폴더 가 기존 HDD에서 rimraf의 60 초 에 비해 15 초 만에 제거되었습니다 .
const lignator = require('lignator');
lignator.remove('./build/');
// 타사 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);
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!')
}
}
참고 URL : https://stackoverflow.com/questions/18052762/remove-directory-which-is-not-empty
'Programing' 카테고리의 다른 글
안드로이드 : ViewPager WRAP_CONTENT를 가질 수 없습니다 (0) | 2020.04.11 |
---|---|
커서를 대기 커서로 바꾸려면 어떻게해야합니까? (0) | 2020.04.11 |
CSS에서 첫 번째 문자를 대문자로 만듭니다. (0) | 2020.04.11 |
base64로 인코딩 된 문자열을 어떻게 디코딩합니까? (0) | 2020.04.11 |
어디에 vs HAVING (0) | 2020.04.11 |