2

Javaの非再帰アルゴリズムで1つのフォルダ/ディレクトリを削除するにはどうすればよいですか? 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()
}

基本的に、このコードはディレクトリをスキャンし、ファイルを削除するか、さらにスキャンするためにサブディレクトリをキューに入れます。スキャンされたディレクトリをスタックに配置し、2 番目のwhileループが正しい順序 (最も深い順) でディレクトリを削除するようにします。

于 2012-07-17T03:45:13.500 に答える
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 に答える
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ます。「正しい」順序で削除することにより、削除をより効率的にします。等

于 2012-07-17T02:49:45.877 に答える
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 に答える
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削除されます。ディレクトリなど、通常でないファイルはスキップされます。

もちろん、メソッドに aFileFilterを追加しlistFiles()て、配列が通常のファイルによってのみ読み込まれるようにするなど、他の同様の代替手段がありますが、実際にはかなり似ています。

ディレクトリ ツリーを削除する場合は、何らかの再帰を使用する必要があります。ただし、別の方法でアプローチすることもできます。これにより、ディレクトリを作成してから、一度に 1 つずつ削除するArrayListことを繰り返すなど、それほど多くの問題が発生しない可能性があります。ArrayListこれは、再帰を減らすのに役立ちます。

于 2012-07-17T02:17:48.090 に答える