Javaの非再帰アルゴリズムで1つのフォルダ/ディレクトリを削除するにはどうすればよいですか? StackOverflowErrors
フォルダーのパスが非常に深い場合を回避するために、非再帰アルゴリズムを使用したいと考えています。
誰かがこの分野でアドバイスを提供してくれませんか。
Javaの非再帰アルゴリズムで1つのフォルダ/ディレクトリを削除するにはどうすればよいですか? StackOverflowErrors
フォルダーのパスが非常に深い場合を回避するために、非再帰アルゴリズムを使用したいと考えています。
誰かがこの分野でアドバイスを提供してくれませんか。
これをテストするのに便利な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
ループが正しい順序 (最も深い順) でディレクトリを削除するようにします。
// 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();
}
再帰を削除するには、コール スタックを明示的なスタックに置き換えて、まだ処理が必要なアイテムを保持します。あなたの場合、現在の親フォルダーを使い終わった後、削除する必要があるすべての親フォルダーを追跡します。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();
}
}
}
}
}
これは、改善するための出発点にすぎません。
重要な部分は、削除するディレクトリを見つけることです。
この疑似コードは、特定のディレクトリの下にあるすべてのディレクトリを見つけるのに役立ちます。
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
ます。「正しい」順序で削除することにより、削除をより効率的にします。等
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);
}
あなたの質問に対する私の解釈は、ディレクトリ内のディレクトリに再帰せずにディレクトリを削除したいということです。この場合、非常に単純なループを使用して削除を実装できます...
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
これは、再帰を減らすのに役立ちます。