2

如何通过 Java 中的非递归算法删除一个文件夹/目录?我想使用非递归算法以避免StackOverflowErrors文件夹具有非常深的路径。

有人可以在这方面提供一些建议。

4

7 回答 7

4

在蹩脚的伪代码中,因为我没有方便的 Java 编译器来测试它:

queue = [ rootDir ]
stack = []

while ( !queue.isEmpty() ) {
    currentDir = queue.take()
    stack.push( currentDir )
    files = currentDir.list()
    for ( f : files ) {
        if ( f.isDirectory() ) {
            queue.add( f )
        } else {
            f.delete()
        }
    }
}

while ( !stack.isEmpty() ) {
    f = stack.pop()
    f.delete()
}

基本上,这段代码应该扫描一个目录,删除文件或排队子目录以进行进一步扫描。它将扫描的目录放在一个堆栈中,以便第二个while循环以正确的顺序删除它们(最深的优先)。

于 2012-07-17T03:45:13.500 回答
3

这是删除文件/文件夹的一般方法:

/**deletes a file/folder recursively, and returns true iff succeeded */
public static boolean deleteQuietly(File file) {
    if (file == null || !file.exists())
        return true;
    if (!file.isDirectory())
        return file.delete();
    LinkedList<File> dirs = new LinkedList<>();
    dirs.add(0, file);
    boolean succeededDeletion = true;
    while (!dirs.isEmpty()) {
        file = dirs.remove(0);
        File[] children = file.listFiles();
        if (children == null || children.length == 0)
            succeededDeletion &= file.delete();
        else {
            dirs.add(0, file);
            for (File child : children)
                if (child.isDirectory())
                    dirs.add(0, child);
                else
                    succeededDeletion &= child.delete();
        }
    }
    return succeededDeletion;
}
于 2015-05-11T10:56:56.260 回答
1

这只是您改进的起点。

关键部分是找出要删除的目录。

这段伪代码应该可以帮助您找出某个目录下的所有目录:

Set<File> allDirectories = new Set<File>();
allDirectories.add(yourStartingDirectory);


while (hasMoreToRead) { 
  hasMoreToRead = false;
  for (File f : allDirectories) {
    if (f.isDirectory() && !allDirectories.contains(f)) {
      allDirectories.add(f);
      hasMoreToRead = true;
    }
  }
}

这只是一个起点,但您应该能够完成其余的工作:避免重新访问allDirectories在先前迭代中处理过的目录;基于allDirectories;执行删除 通过以“正确”顺序删除来提高删除效率;ETC

于 2012-07-17T02:49:45.877 回答
1
// Deletes all files and subdirectories under dir.
// Returns true if all deletions were successful.
// If a deletion fails, the method stops attempting to delete and returns false.
public static boolean deleteDir(File dir) {
    if (dir.isDirectory()) {
        String[] children = dir.list();
        for (int i=0; i<children.length; i++) {
            boolean success = deleteDir(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
    }

    // The directory is now empty so delete it
    return dir.delete();
}
于 2012-07-17T03:07:32.560 回答
1

要删除递归,您可以用显式堆栈替换调用堆栈以保存您仍需要处理的项目。在您的情况下,您可以跟踪完成当前文件夹后需要删除的所有父文件夹。这是一个使用 LinkedList 作为堆栈的示例:

public static void rmdir(File dir) {
    LinkedList<File> dirs = new LinkedList<File>();
    dirs.push(dir);

    while (dirs.peek() != null) {
        dir = dirs.pop();
        File[] contents = dir.listFiles();

        if (contents.length == 0) {
            dir.delete();
        } else {
            dirs.push(dir);

            for(File content : contents) {
                if (content.isDirectory()) {
                    dirs.push(content);
                } else {
                    content.delete();
                }
            }
        }
    }
}
于 2012-07-17T05:46:16.983 回答
0

我对您的问题的解释是您想删除一个目录而不递归到其中的目录。在这种情况下,您可以使用非常简单的循环来实现删除...

File directory = new File("c:\\directory_path")
if (!directory.exists()){
    return;
}

File[] files = directory.listFiles();
for (int i=0;i<files.length;i++){
    if (files[i].isFile()){
        boolean deleted = files[i].delete();
        if (!deleted){
            System.out.println("Problem deleting file " + files[i].getAbsolutePath());
        }
    }
}

这将列出Files数组中的所有目录,然后遍历它们。如果文件是normal file,它将被删除。将跳过非正常文件,例如目录。

当然,还有其他类似的替代方案,例如FileFilterlistFiles()方法中添加 a 以便数组仅由普通文件填充,但实际上非常相似。

如果要删除目录树,则必须使用某种递归。不过,您可以采用不同的方法来处理它,这可能不会给您带来太多问题,例如构建一个ArrayList目录,然后ArrayList一次又一次地删除它们。这将有助于减少递归。

于 2012-07-17T02:17:48.090 回答
0
public static final void delete(File file) throws IOException
{
    if (!file.exists())
        throw new IllegalArgumentException("File does not exist: " + file);

    if (file.isFile())
    {
        simpleDelete(file);
        return;
    }

    Deque<File> dirsQueue = new ArrayDeque<File>();
    dirsQueue.push(file);

    for (File dir; (dir = dirsQueue.peekLast()) != null;)
    {
        File[] children = dir.listFiles();

        if (children == null)
            throw new IOException("Unable to read directory: " + dir);

        if (children.length == 0)
        {
            simpleDelete(dir);
            dirsQueue.removeLast();
            continue;
        }

        for (File child : children)
        {
            if (child.isDirectory())
                dirsQueue.addLast(child);
            else
                simpleDelete(child);
        }
    }
}

private static final void simpleDelete(File file) throws IOException
{
    if (!file.delete())
        throw new IOException("Unable to delete " + (file.isDirectory() ? "directory" : "file") + ": " + file);
}
于 2013-09-04T05:39:52.173 回答