programing

비어 있지 않은 디렉터리 제거

muds 2023. 5. 16. 23:13
반응형

비어 있지 않은 디렉터리 제거

노드 응용 프로그램에서 일부 파일이 있지만 빈 디렉터리에서만 작동하는 디렉터리를 제거해야 합니다.어떻게 해야 하나요?

Node.js 14.14.0에서 권장되는 방법은 다음과 같습니다.

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

.rimraf(https://npmjs.org/package/rimraf) .와 동일한 기능을 제공합니다.rm -Rf

비동기 사용:

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

동기화 사용량:

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

폴더를 동기화하여 제거하려면

    const fs = require('fs');
    const Path = require('path');

    const deleteFolderRecursive = function (directoryPath) {
    if (fs.existsSync(directoryPath)) {
        fs.readdirSync(directoryPath).forEach((file, index) => {
          const curPath = path.join(directoryPath, file);
          if (fs.lstatSync(curPath).isDirectory()) {
           // recurse
            deleteFolderRecursive(curPath);
          } else {
            // delete file
            fs.unlinkSync(curPath);
          }
        });
        fs.rmdirSync(directoryPath);
      }
    };

은 대분의사는자를 합니다.fsNode.js를 사용하면 파일을 처리하는 "Unix 방식"에 가까운 기능을 사용할 수 있습니다.저는 모든 멋진 것들을 가져오기 위해 fs-extra를 사용하고 있습니다.

fs-extra에는 vanilla Node.jsfs 패키지에 포함되지 않은 메서드가 포함되어 있습니다.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);

) , Node v14 (2020년 10월) 기준,fs모듈이 있습니다.fs.rm그리고.rs.rmSyncrecursive, 비어 있지 연결 를 지원합니다.

https://nodejs.org/docs/latest-v14.x/api/fs.html#fs_fs_rm_path_options_callback

이제 다음과 같은 작업을 수행할 수 있습니다.

const fs = require('fs');
fs.rm('/path/to/delete', { recursive: true }, () => console.log('done'));

또는:

const fs = require('fs');
fs.rmSync('/path/to/delete', { recursive: true });
console.log('done');

@oconnecp(https://stackoverflow.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);
    }
}

나는 보통 오래된 스레드를 부활시키지 않지만 여기에는 많은 것들이 있고 산스는 이 모든 것이 나에게 지나치게 복잡해 보입니다.

현대 노드(>= 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);
};

다른 한편으로 경로 횡단 공격에 대한 가드는 다음과 같은 이유로 이 기능에 적합하지 않습니다.

  1. 그것은 단일 책임 원칙에 근거한 범위를 벗어납니다.
  2. 이 기능이 아닌 호출자가 처리해야 합니다.이것은 명령줄과 유사합니다.rm -rf가 인수를 사용할 수 있도록 입니다.rm -rf /청하면보호하는 것은 대본의 책임일 것입니다.rm프로그램 자체.
  3. 이 함수는 참조 프레임이 없기 때문에 이러한 공격을 확인할 수 없습니다.다시 말하지만, 그것은 경로 트래버설을 비교하기 위한 참조를 제공하는 의도의 맥락을 가진 호출자의 책임입니다.
  4. 심볼릭 링크는 문제가 되지 않습니다..isDirectory()이라false및.sym-delinked에 설명합니다.

마지막으로, 이 재귀가 실행되는 동안 이 스크립트 외부에서 항목 중 하나가 적절한 시점에 연결 해제되거나 삭제되면 재귀 오류가 발생할 수 있는 희귀한 경합 조건이 있습니다.이 시나리오는 대부분의 환경에서 일반적이지 않으므로 간과할 수 있습니다.그러나 필요한 경우(일부 에지 사례의 경우) 다음과 같은 좀 더 복잡한 예를 사용하여 이 문제를 완화할 수 있습니다.

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()함수 합니다.끝에 있는 실제 디렉터리를 제거합니다.누락된 재귀를 수정합니다.

노드 문서에서 볼 수 있습니다.

유사한 동작을 가져오려면 다음과 같이 하십시오.rm -rf명령, Unix 령명, 사용 사용fs.rm() { recursive: true, force: true }.

예(ESM)

import { rm } from 'node:fs/promises';

await rm('/path/to', { recursive: true, force: true });

나는 폴더 제거라는 기능을 썼습니다.위치에 있는 모든 파일과 폴더를 재귀적으로 제거합니다.그것이 필요로 하는 유일한 패키지는 비동기입니다.

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

다음은 @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);
            });
        });
    });
};

[EDIT: node.js v15.5.0 사용]

여기에 게시된 솔루션 중 일부를 사용해 본 결과 다음과 같은 사용 중지 경고가 발생했습니다.

(노드:13202) [DEP0147] 사용 중지 경고:Node.js 이후 버전에서는 경로가 없거나 파일인 경우 fs.rmdir(경로, {recursive:true })가 느려집니다.대신 fs.rm(경로, {recursive: true, force: true }) 사용

fs.rm(path, { recursive: true, force: true });잘작니다합과 함께 잘합니다.fs.rmSync(path, { recursive: true, force: true });차단 버전을 사용하려는 경우.

노드 8+를 사용하는 경우 비동기성을 원하지만 외부 종속성을 원하지 않는 경우 비동기/대기 버전은 다음과 같습니다.

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);
    }
}
const fs = require("fs");
fs.rmdir("./test", { recursive: true }, (err) => {
  if (err) {
    console.error(err);
  }
});

을 합니다.recursive: true그리고 경로의 합니다. ( about the pathtest루트에 디렉터리가 있습니다.)

2020년 업데이트

버전 12.10.0부터는 옵션에 대한 recursiveOption이 추가되었습니다.

재귀 삭제는 실험적인 입니다.

따라서 동기화를 위해 다음 작업을 수행합니다.

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

또는 비동기의 경우:

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

문서에 따르면,fsPromises은(는) 니다합공제를현을 합니다.recursive적어도 Windows의 경우에는 디렉터리와 그 안에 있는 모든 파일을 제거하는 실험적인 옵션입니다.

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

있습니까?recursive: trueLinux 및 MacOS에서 파일을 제거하시겠습니까?

설명

Node에는 Node.js v14를 할 수 .require("fs").promises.rm약속을 사용하여 파일을 제거하는 기능.첫 번째 인수는 제거할 파일 또는 폴더(존재하지 않는 파일도 포함)입니다.당신은 할 수 .recursive그리고.force rm가 셸 명령 -rf옵션들.

"use strict";

require("fs").promises.rm("directory", {recursive: true, force: true}).then(() => {
  console.log("removed");
}).catch(error => {
  console.error(error.message);
});

Node.js v14 설명서

Mozilla 개발자의 약속 문서

rm 매뉴얼 설정

저는 여기에 도착했습니다.gulp더 많은 소식을 듣고 싶어서 편지를 쓰고 있습니다

를 사용하여 파일 및 폴더를 삭제하려면 다음을 추가해야 합니다./**재귀 삭제를 위해.

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

Node.에서는 Node.js(12.10.0)가 됩니다.rmdir스타일 함수 , 및 새 실험 옵션이 있습니다.recursive비어 있지 않은 디렉터리를 삭제할 수 있습니다.

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

GitHub 관련 홍보: https://github.com/nodejs/node/pull/29168

fs.promise를 사용한 @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);
    }
};

에는 "/기다리다"를 할 수 .fs/promisesAPI.API.

const fs = require('fs/promises');

const removeDir = async (dirPath) => {
  await fs.rm(dirPath, {recursive: true});
}

폴더에 있는 단일 파일의 경로를 알고 해당 파일이 들어 있는 폴더를 삭제하려는 경우.

const fs = require('fs/promises');
const path = require('path');

const removeDir = async (filePath) => {
  const { dir } = path.parse(filePath);
  await fs.rm(dir, { recursive: true });
}
return new Promise((resolve, reject) => {
  const fs = require("fs");
  // directory path
  const dir = "your/dir";

  // delete directory recursively <------
  fs.rmdir(dir, { recursive: true }, (err) => {
    if (err) {
      reject(err);
    }
    resolve(`${dir} is deleted!`);
  });
});

그냥 usermdir module! 쉽고 간단합니다.

빠르고 더러운 방법(테스트용일 수 있음)은 직접 사용할 수 있습니다.exec또는spawnOS 호출을 호출하여 디렉터리를 제거하는 메서드입니다.NodeJs child_process에 대해 자세히 알아보십시오.

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

단점은 다음과 같습니다.

  1. 기본 OS에 의존합니다. 즉, 동일한 방법이 unix/linux에서 실행되지만 Windows에서는 실행되지 않을 수 있습니다.
  2. 조건이나 오류가 발생한 경우 프로세스를 하이잭할 수 없습니다.기본 OS에 작업을 부여하고 종료 코드가 반환될 때까지 기다립니다.

이점:

  1. 이러한 프로세스는 비동기적으로 실행될 수 있습니다.
  2. 명령의 출력/오류를 수신할 수 있으므로 명령 출력이 손실되지 않습니다.작업이 완료되지 않은 경우 오류 코드를 확인하고 다시 시도할 수 있습니다.

는 사상의패는입니다.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))
}

비동기식 접근법에서, 비어있지 않은 dir를 삭제하기 위해서는

rmdir(path,{recursive:true,force:true}
rm(path,{recursive:true,force:true}

효과가 있을 것

코드 조각:

const fsp = require("fs/promises");

deleteDirRecursively("./b");
removeRecursively("./BCD/b+");

async function deleteDirRecursively(dirPath) {
  try {
    // fsPromises.rmdir() on a file (not a directory) results in the promise being rejected
    // with an ENOENT error on Windows and an ENOTDIR error on POSIX.
    // To get a behavior similar to the rm -rf Unix command,
    // use fsPromises.rm() with options { recursive: true, force: true }.
    //will not thorw error if dir is empty
    //will thow error if dir is not present
    await fsp.rmdir(dirPath, { recursive: true, force: true });
    console.log(dirPath, "deleted successfully");
  } catch (err) {
    console.log(err);
  }

async function removeRecursively(path) {
  try {
    //has ability to remove both file and dir
    //can delete dir recursively and forcefully
    //will delete an empty dir.
    //will remove all the contents of a dir.
    // the only difference between rmdir and rm is that rmdir can only delete dir's
    await fsp.rm(path, { recursive: true, force: true });
    console.log(path, "deleted successfully");
  } catch (err) {
    console.log(err);
  }
}

초고속 및 장애 방지

당신은 할 수 .lignatorpackage(https://www.npmjs.com/package/lignator), 는 어떤 비동기 코드(예: rimraf)보다 빠르고 장애 방지 기능이 뛰어납니다(특히 파일 제거가 즉각적으로 이루어지지 않고 다른 프로세스에 의해 파일이 잠길 수 있는 Windows의 경우).

이전 HDD에서 Rimraf의 60초에 비해 Windows에서 4,36GB의 데이터, 28042개의 파일, 4217개의 폴더가 15초 만에 제거되었습니다.

const lignator = require('lignator');

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

동기화 폴더를 파일과 함께 제거하거나 파일만 제거합니다.

저는 대단한 기부자도 아니고 기부자도 아니지만 이 문제에 대한 좋은 해결책을 찾지 못해서 제 길을 찾아야 했습니다.그러니 마음에 들었으면 좋겠어요 :)

여러 개의 중첩된 디렉토리 및 하위 디렉토리에서 완벽하게 작동합니다.함수를 재귀화할 때 '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);
        }

2020년 정답

npm 스크립트에서 이 작업을 수행하려면 다음 명령을 사용할 경우 타사 패키지를 미리 설치할 필요가 없습니다.npx

예를 들어, 를 실행할 때 dist 및 .cache 폴더를 삭제하려는 경우npm run clean그런 다음 이 명령을 패키지에 추가합니다.제이손

{
  "scripts": {
    "clean": "npx rimraf dist .cache"
  }
}

모든 작동 시스템에서 작동합니다.

또 다른 대안은 약속된 버전의 모듈을 제공하는 모듈을 사용하는 것입니다.

그런 다음 다음 다음과 같이 쓸 수 있습니다.

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)

참고: 비동기/동기화를 사용하려면 최신 nodejs 버전(7.6+)이 필요합니다.

저는 이렇게 작고 흔한 것을 위한 추가 모듈 없이 이것을 할 수 있는 방법이 있었으면 좋겠지만, 이것이 제가 생각할 수 있는 최선입니다.

업데이트: 이제 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);
    });
}

언급URL : https://stackoverflow.com/questions/18052762/remove-directory-which-is-not-empty

반응형