답변:
Apache의 commons-io를 확인해야합니다 . 그것은 당신이 원하는 것을 할 FileUtils 클래스를 가지고 있습니다.
FileUtils.deleteDirectory(new File("directory"));
Java 7을 사용하면 마지막 으로 안정적인 symlink 탐지를 통해이를 수행 할 수 있습니다 . (아파치의 commons-io는 현재 신뢰할 수있는 symlink 감지 기능 을 가지고 있다고 생각하지 않습니다.mklink
.)
역사를 위해 자바 7 이전 답변이 있습니다.이 답변 은 심볼릭 링크 를 따릅니다.
void delete(File f) throws IOException {
if (f.isDirectory()) {
for (File c : f.listFiles())
delete(c);
}
if (!f.delete())
throw new FileNotFoundException("Failed to delete file: " + f);
}
foo
링크와 foo/link
같은 것을 link->/
호출, delete(new File(foo))
사용자가 허용 될 때, 파일 시스템의 많은으로 삭제됩니다 !!
Java 7 이상에서는 Files
클래스 를 사용할 수 있습니다 . 코드는 매우 간단합니다.
Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
super.postVisitDirectory(dir, exc);
있도록 postVisitDirectory
메소드를 호출해야합니다 .
시작 디렉토리를 포함하여 모든 파일과 디렉토리를 재귀 적으로 삭제하는 단일 라이너 솔루션 (Java8) :
Files.walk(Paths.get("c:/dir_to_delete/"))
.map(Path::toFile)
.sorted((o1, o2) -> -o1.compareTo(o2))
.forEach(File::delete);
우리는 역순으로 비교자를 사용합니다. 그렇지 않으면 File :: delete는 비어 있지 않은 디렉토리를 삭제할 수 없습니다. 따라서 디렉토리를 유지하고 파일 만 삭제하려면 sorted ()에서 비교기를 제거 하거나 정렬을 완전히 제거하고 파일 필터를 추가하십시오.
Files.walk(Paths.get("c:/dir_to_delete/"))
.filter(Files::isRegularFile)
.map(Path::toFile)
.forEach(File::delete);
.sorted(Comparator.reverseOrder())
제안 Comparator::reverseOrder
이 작동 하지 않는 것입니다. 참조 : stackoverflow.com/questions/43036611/…
.sorted((f1, f2) -> f2.compareTo(f1))
, 비교 f2
와 f1
대신 f1
에 f2
.
Java 7은 symlink 처리를 사용하여 디렉토리를 걷는 것에 대한 지원을 추가했습니다.
import java.nio.file.*;
public static void removeRecursive(Path path) throws IOException
{
Files.walkFileTree(path, new SimpleFileVisitor<Path>()
{
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException
{
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
{
// try to delete the file anyway, even if its attributes
// could not be read, since delete-only access is
// theoretically possible
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
{
if (exc == null)
{
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
else
{
// directory iteration failed; propagate exception
throw exc;
}
}
});
}
나는 이것을 플랫폼 특정 메소드 (이 테스트되지 않은 코드에서)의 대체로 사용 합니다.
public static void removeDirectory(Path directory) throws IOException
{
// does nothing if non-existent
if (Files.exists(directory))
{
try
{
// prefer OS-dependent directory removal tool
if (SystemUtils.IS_OS_WINDOWS)
Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
else if (SystemUtils.IS_OS_UNIX)
Processes.execute("/bin/rm", "-rf", directory.toString());
}
catch (ProcessExecutionException | InterruptedException e)
{
// fallback to internal implementation on error
}
if (Files.exists(directory))
removeRecursive(directory);
}
}
(SystemUtils는 Apache Commons Lang의 것 입니다. 프로세스는 개인용이지만 그 동작은 분명해야합니다.)
방금 내 솔루션이 erickson과 거의 동일하고 정적 방법으로 패키지 된 것을 보았습니다. 이것을 어딘가에 떨어 뜨리면 (아시다시피) 아주 간단한 것을 위해 모든 Apache Commons를 설치하는 것보다 훨씬 가볍습니다.
public class FileUtils {
/**
* By default File#delete fails for non-empty directories, it works like "rm".
* We need something a little more brutual - this does the equivalent of "rm -r"
* @param path Root File Path
* @return true iff the file and all sub files/directories have been removed
* @throws FileNotFoundException
*/
public static boolean deleteRecursive(File path) throws FileNotFoundException{
if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
boolean ret = true;
if (path.isDirectory()){
for (File f : path.listFiles()){
ret = ret && deleteRecursive(f);
}
}
return ret && path.delete();
}
}
스택이 있고 재귀 적 방법이없는 솔루션 :
File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
if (stack.lastElement().isDirectory()) {
currList = stack.lastElement().listFiles();
if (currList.length > 0) {
for (File curr: currList) {
stack.push(curr);
}
} else {
stack.pop().delete();
}
} else {
stack.pop().delete();
}
}
list*
class 의 메소드에 주의하십시오 java.io.File
. Javadoc에서 : "이 추상 경로 이름이 디렉토리를 나타내지 않거나 I / O 오류가 발생하면 널을 리턴합니다." 그래서 : if (currList.length > 0) {
이된다if (null != currList && currList.length > 0) {
Spring이 있다면 FileSystemUtils.deleteRecursively 사용할 수 있습니다 :
import org.springframework.util.FileSystemUtils;
boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
구아바 는 구아바 9Files.deleteRecursively(File)
까지 지원 했다 .
에서 구아바 10 :
더 이상 사용되지 않습니다. 이 방법은 심볼릭 링크 감지 및 경쟁 조건이 열악합니다. 이 기능은
rm -rf
또는 과 같은 운영 체제 명령을 셸링하여 만 적절히 지원할 수 있습니다del /s
. 이 방법은 Guava 릴리스 11.0의 Guava에서 제거 될 예정입니다.
따라서 구아바 11 에는 그러한 방법이 없습니다 .
for(Path p : Files.walk(directoryToDelete).
sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
toArray(Path[]::new))
{
Files.delete(p);
}
또는 다음을 처리하려는 경우 IOException
:
Files.walk(directoryToDelete).
sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
forEach(p -> {
try { Files.delete(p); }
catch(IOException e) { /* ... */ }
});
Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
walk
방법은 이미 깊이 우선 순회를 보장합니다.
Collections.reverseOrder()
코드를 for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))
정적으로 가져온 것으로 가정 하여 비교기를 재활용 할 수 있습니다 .
Comparator.reverseOrder
인가요? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
public void deleteRecursive(File path){
File[] c = path.listFiles();
System.out.println("Cleaning out folder:" + path.toString());
for (File file : c){
if (file.isDirectory()){
System.out.println("Deleting file:" + file.toString());
deleteRecursive(file);
file.delete();
} else {
file.delete();
}
}
path.delete();
}
static public void deleteDirectory(File path)
{
if (path == null)
return;
if (path.exists())
{
for(File f : path.listFiles())
{
if(f.isDirectory())
{
deleteDirectory(f);
f.delete();
}
else
{
f.delete();
}
}
path.delete();
}
}
f.delete()
아래 deleteDirectory(f)
때문에 의지 NoSuchFileException을 던져 deleteDirectory(f)
이미 해당 파일을 삭제합니다. 에 deleteDirectory(f)
의해 전달 되고 삭제 될 때 모든 디렉토리는 경로 가됩니다 path.delete()
. 따라서 섹션 f.delete()
에서 필요하지 않습니다 if f.isDerectory
. 따라서 f.delete();
deleteDirectory (f)에서 삭제 하면 작동합니다.
심볼릭 링크와 위의 코드로 실패하는 두 가지 방법은 ... 솔루션을 모릅니다.
테스트를 작성하려면 다음을 실행하십시오.
echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete
테스트 파일 및 테스트 디렉토리가 표시됩니다.
$ ls testfile dirtodelete
testfile
dirtodelete:
linktodelete
그런 다음 commons-io deleteDirectory ()를 실행하십시오. 파일을 찾을 수 없다는 메시지가 나타납니다. 다른 예제가 무엇인지 잘 모르겠습니다. Linux rm 명령은 단순히 링크를 삭제하고 디렉토리의 rm -r도 삭제합니다.
Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete
테스트를 작성하려면 다음을 실행하십시오.
mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete
테스트 파일 및 테스트 디렉토리가 표시됩니다.
$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete
testdir:
testfile
그런 다음 commons-io deleteDirectory () 또는 사람들이 게시 한 예제 코드를 실행하십시오. 디렉토리뿐만 아니라 삭제되는 디렉토리 외부의 테스트 파일을 삭제합니다. 디렉토리를 암시 적으로 참조 해제하고 내용을 삭제합니다. rm -r은 링크 만 삭제합니다. "find -L dirtodelete -type f -exec rm {} \;"과 같이 역 참조 된 파일을 삭제하십시오.
$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:
당신은 사용할 수 있습니다 :
org.apache.commons.io.FileUtils.deleteQuietly(destFile);
예외를 던지지 않고 파일을 삭제합니다. 파일이 디렉토리이면 해당 디렉토리와 모든 서브 디렉토리를 삭제하십시오. File.delete ()와이 메소드의 차이점은 다음과 같습니다. 삭제할 디렉토리가 비어있을 필요는 없습니다. 파일이나 디렉토리를 삭제할 수없는 경우 예외가 발생하지 않습니다.
메소드에서 예외가 발생하는 접근 방식과 일관되게 예외를 처리하는 최적의 솔루션은 항상 해당 메소드가 시도한 (및 실패한) 조치를 설명해야합니다.
private void deleteRecursive(File f) throws Exception {
try {
if (f.isDirectory()) {
for (File c : f.listFiles()) {
deleteRecursive(c);
}
}
if (!f.delete()) {
throw new Exception("Delete command returned false for file: " + f);
}
}
catch (Exception e) {
throw new Exception("Failed to delete the folder: " + f, e);
}
}
레거시 프로젝트에서는 기본 Java 코드를 작성해야합니다. 이 코드는 Paulitex 코드와 비슷합니다. 저거 봐:
public class FileHelper {
public static boolean delete(File fileOrFolder) {
boolean result = true;
if(fileOrFolder.isDirectory()) {
for (File file : fileOrFolder.listFiles()) {
result = result && delete(file);
}
}
result = result && fileOrFolder.delete();
return result;
}
}
그리고 단위 테스트 :
public class FileHelperTest {
@Before
public void setup() throws IOException {
new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
}
@Test
public void deleteFolderWithFiles() {
File folderToDelete = new File("FOLDER_TO_DELETE");
Assert.assertTrue(FileHelper.delete(folderToDelete));
Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
}
}
다음은 명령 행 인수를 허용하는 기본 본 방법입니다. 자체 오류 검사를 추가하거나 적합한 방식으로 수정해야합니다.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class DeleteFiles {
/**
* @param intitial arguments take in a source to read from and a
* destination to read to
*/
public static void main(String[] args)
throws FileNotFoundException,IOException {
File src = new File(args[0]);
if (!src.exists() ) {
System.out.println("FAILURE!");
}else{
// Gathers files in directory
File[] a = src.listFiles();
for (int i = 0; i < a.length; i++) {
//Sends files to recursive deletion method
fileDelete(a[i]);
}
// Deletes original source folder
src.delete();
System.out.println("Success!");
}
}
/**
* @param srcFile Source file to examine
* @throws FileNotFoundException if File not found
* @throws IOException if File not found
*/
private static void fileDelete(File srcFile)
throws FileNotFoundException, IOException {
// Checks if file is a directory
if (srcFile.isDirectory()) {
//Gathers files in directory
File[] b = srcFile.listFiles();
for (int i = 0; i < b.length; i++) {
//Recursively deletes all files and sub-directories
fileDelete(b[i]);
}
// Deletes original sub-directory file
srcFile.delete();
} else {
srcFile.delete();
}
}
}
도움이 되길 바랍니다.
이 문제에 대한 해결책은 erickson의 답변 코드를 사용하여 File 클래스의 delete 메소드를 다시 구현하는 것일 수 있습니다.
public class MyFile extends File {
... <- copy constructor
public boolean delete() {
if (f.isDirectory()) {
for (File c : f.listFiles()) {
return new MyFile(c).delete();
}
} else {
return f.delete();
}
}
}
Commons IO 및 <Java SE 7없이
public static void deleteRecursive(File path){
path.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
pathname.listFiles(this);
pathname.delete();
} else {
pathname.delete();
}
return false;
}
});
path.delete();
}
file.delete ()를 사용하여 파일을 쉽게 삭제할 수 있지만 삭제하려면 디렉토리를 비워야합니다. 재귀를 사용하여 쉽게 수행하십시오. 예를 들면 다음과 같습니다.
public static void clearFolders(String[] args) {
for(String st : args){
File folder = new File(st);
if (folder.isDirectory()) {
File[] files = folder.listFiles();
if(files!=null) {
for(File f: files) {
if (f.isDirectory()){
clearFolders(new String[]{f.getAbsolutePath()});
f.delete();
} else {
f.delete();
}
}
}
}
}
}
안전한 사용을 위해 3 가지 안전 기준을 가진이 루틴을 코딩했습니다.
package ch.ethz.idsc.queuey.util;
import java.io.File;
import java.io.IOException;
/** recursive file/directory deletion
*
* safety from erroneous use is enhanced by three criteria
* 1) checking the depth of the directory tree T to be deleted
* against a permitted upper bound "max_depth"
* 2) checking the number of files to be deleted #F
* against a permitted upper bound "max_count"
* 3) if deletion of a file or directory fails, the process aborts */
public final class FileDelete {
/** Example: The command
* FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
* deletes given directory with sub directories of depth of at most 2,
* and max number of total files less than 1000. No files are deleted
* if directory tree exceeds 2, or total of files exceed 1000.
*
* abort criteria are described at top of class
*
* @param file
* @param max_depth
* @param max_count
* @return
* @throws Exception if criteria are not met */
public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
return new FileDelete(file, max_depth, max_count);
}
// ---
private final File root;
private final int max_depth;
private int removed = 0;
/** @param root file or a directory. If root is a file, the file will be deleted.
* If root is a directory, the directory tree will be deleted.
* @param max_depth of directory visitor
* @param max_count of files to delete
* @throws IOException */
private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
this.root = root;
this.max_depth = max_depth;
// ---
final int count = visitRecursively(root, 0, false);
if (count <= max_count) // abort criteria 2)
visitRecursively(root, 0, true);
else
throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
}
private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
if (max_depth < depth) // enforce depth limit, abort criteria 1)
throw new IOException("directory tree exceeds permitted depth");
// ---
int count = 0;
if (file.isDirectory()) // if file is a directory, recur
for (File entry : file.listFiles())
count += visitRecursively(entry, depth + 1, delete);
++count; // count file as visited
if (delete) {
final boolean deleted = file.delete();
if (!deleted) // abort criteria 3)
throw new IOException("cannot delete " + file.getAbsolutePath());
++removed;
}
return count;
}
public int deletedCount() {
return removed;
}
public void printNotification() {
int count = deletedCount();
if (0 < count)
System.out.println("deleted " + count + " file(s) in " + root);
}
}
예를 들어 보자.
import java.io.File;
import java.io.IOException;
public class DeleteDirectory
{
private static final String folder = "D:/project/java";
public static void main(String[] args) throws IOException
{
File fl = new File(folder);
if(!fl.exists()) // checking if directory exists
{
System.out.println("Sorry!! directory doesn't exist.");
}
else
{
DeleteDirectory dd = new DeleteDirectory();
dd.deleteDirectory(fl);
}
}
public void deleteDirectory(File file) throws IOException
{
if(file.isDirectory())
{
if(file.list().length == 0)
{
deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
}
else
{
File fe[] = file.listFiles();
for(File deleteFile : fe)
{
deleteDirectory(deleteFile); // recursive call
}
if(file.list().length == 0)
{
deleteEmptyDirectory(file);
}
}
}
else
{
file.delete();
System.out.println("File deleted : " + file.getAbsolutePath());
}
}
private void deleteEmptyDirectory(File fi)
{
fi.delete();
System.out.println("Directory deleted : " + fi.getAbsolutePath());
}
}
자세한 내용은 아래 리소스를 참조하십시오
rm -rf
보다 성능 이 훨씬 뛰어 났습니다 FileUtils.deleteDirectory
.광범위한 벤치마킹 결과, 사용하는 것이 사용 rm -rf
하는 것보다 여러 배 빠릅니다.FileUtils.deleteDirectory
.
물론 작거나 간단한 디렉토리가 있다면 중요하지 않지만 우리의 경우에는 기가 바이트와 깊게 중첩 된 하위 디렉토리가있어 10 분 이상 걸리고 FileUtils.deleteDirectory
1 분 밖에 걸리지 않습니다 rm -rf
.
이를 수행하기위한 대략적인 Java 구현은 다음과 같습니다.
// Delete directory given and all subdirectories and files (i.e. recursively).
//
static public boolean deleteDirectory( File file ) throws IOException, InterruptedException {
if ( file.exists() ) {
String deleteCommand = "rm -rf " + file.getAbsolutePath();
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec( deleteCommand );
process.waitFor();
return true;
}
return false;
}
크거나 복잡한 디렉토리를 다루는 경우 시도해 볼 가치가 있습니다.
구아바 는 하나의 라이너를 제공합니다.MoreFiles.deleteRecursively()
.
공유 된 많은 예제와 달리, 심볼릭 링크를 설명하며 기본적으로 제공된 경로 외부의 파일을 삭제하지 않습니다.