(明らかに)無限に再帰的なフォルダーを削除する


46

どういうわけか、古いServer 2008(R2ではない)ボックスの1つが、一見無限に再帰するフォルダーを開発しました。これは、バックアップエージェントがフォルダーに再帰して戻ろうとするので、バックアップでhavockを実行しています。

フォルダ構造は次のようになります。

C:\Storage\Folder1
C:\Storage\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1\Folder1

... 等々。これは、90年代に私たちが一緒にプレイしたマンデルブロセットの 1つに似ています。

私はもう試した:

  • エクスプローラーから削除します。ええ、私は楽観主義者です。
  • RMDIR C:\Storage\Folder1 /Q/S -これは戻ります The directory is not empty
  • ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE -これは、robocopy.exeがクラッシュする前に数分間フォルダーをスピンします。

誰もこのフォルダを永久に殺す方法を提案できますか?


1
/MIR代わりに試してみます:笑いのためだけにROBOCOPY /MIR C:\temp\EmptyDirectory C:\Storage\Folder1実行する価値があるかもしれませんchkdsk
jscott

1
/MIR長持ちするように見えましたが、最終的には爆撃も終了しました(「ロボットコピーは動作を停止しました」)。私は少し怖いですchkdsk; ...これはかなり古いサーバーであり、私はこの問題は大きなファイルシステムの問題を示すものであることを心配している
KenD

7
Linux(Ubuntu / Centos / Fedora / ...)デスクトップトライアルCDから起動して、そこからフォルダーを削除してみてください。
ガントラムBLOHMはモニカ・サポート

2
@KenDファイルシステムの破損の問題が疑われる場合は、まずファイルシステムの修復を試してください。ディレクトリ削除のトリックを試すと事態が悪化する可能性があります。
-jscott

1
あなたがいた場合(下のあなたの答えから)、ディレクトリは、単に非常に深い、無限ではなかったので、CygWinのUnxUtilsがインストールされ、使用することができ、find深さ最初のディレクトリの削除を行うには:find Storage/Folder1 -depth -exec rmdir {} \;
ジョニー

回答:


45

有益なアドバイスをありがとう。

StackOverflowの領域に迷い込んで、このC#コードの断片をノックアップすることで問題を解決しました。長いファイルパスへのアクセスの問題に特に対処するDelimon.Win32.IOライブラリを使用します。

これが他の誰かを助けることができる場合に備えて、ここにコードがあります-それは私が何らかの形で立ち往生していた約1600レベルの再帰を通過し、それらをすべて削除するのに約20分かかりました。

using System;
using Delimon.Win32.IO;

namespace ConsoleApplication1
{
    class Program
    {
        private static int level;
        static void Main(string[] args)
        {
            // Call the method to delete the directory structure
            RecursiveDelete(new DirectoryInfo(@"\\server\\c$\\storage\\folder1"));
        }

        // This deletes a particular folder, and recurses back to itself if it finds any subfolders
        public static void RecursiveDelete(DirectoryInfo Dir)
        {
            level++;
            Console.WriteLine("Now at level " +level);
            if (!Dir.Exists)
                return;

            // In any subdirectory ...
            foreach (var dir in Dir.GetDirectories())
            {
                // Call this method again, starting at the subdirectory
                RecursiveDelete(dir);
            }

            // Finally, delete the directory, and any files below it
            Dir.Delete(true);
            Console.WriteLine("Deleting directory at level " + level);
            level--;
        }
    }
}

2
.Delete(通常System.IOバージョンではなく)Delimonバージョンを使用してみましたが、例外はスローされませんでしたが、何も実行されないようでした。確かに、上記の方法を使用した再帰には時間がかかり.Delete、5〜10秒間しか噛みませんでした。たぶんそれはいくつかのディレクトリで欠けて、それからあきらめましたか?
KenD

4
そもそもそれがどのように始まったかを理解したことがありますか?本当にひどく書かれたユーザーランドプログラムのせいのように聞こえます。
パルティアショット


2
余談ですが、フォルダーには何かが入っていましたか?あなたはどのような間隔で決定することができた場合は、再帰的なフォルダが作成され、乗算再帰の数によって、あなたは(うまくいけば)...この問題が始まったときの大まかな期間を取得すること
は、Get-HomeByFiveOClock

8
うわー、これを解決してくれてうれしいです。参考までに、この種の状況に対するマイクロソフトが公式にサポートした修正は「ボリュームの再フォーマット」です。ええ、真剣に。:/
HopelessN00b

25

再帰的な接合点になる可能性があります。このようなことはjunctionSysinternalsのファイルおよびディスクユーティリティを使用して作成できます。

mkdir c:\Hello
junction c:\Hello\Hello c:\Hello

これで、c:\ Hello \ Hello \ Hello ....をたどり着くことができます(MAX_PATHに達するまで、ほとんどのコマンドで260文字ですが、一部のWindows API関数では32,767文字です)。

ディレクトリリストは、ジャンクションであることを示しています。

C:\>dir c:\hello
 Volume in drive C is DR1
 Volume Serial Number is 993E-B99C

 Directory of c:\hello

12/02/2015  08:18 AM    <DIR>          .
12/02/2015  08:18 AM    <DIR>          ..
12/02/2015  08:18 AM    <JUNCTION>     hello [\??\c:\hello]
               0 File(s)              0 bytes
               3 Dir(s)  461,591,506,944 bytes free

C:\>

junctionユーティリティを使用して削除するには:

junction -d c:\Hello\Hello

4
残念ながら、DIRちょうどショー私平野オーレディレクトリ-私は怖い任意の接合の兆候
KenD

2
で簡単な二重チェックを行うことはできますjunction -s C:\Storage\Folder1 か?
ブライアン

3
No reparse points found:(
KenD

3
何が実際のサブディレクトリのそのような混乱を作成したのだろうか。
ブライアン

2
dir /a特定の名前を指定せずに「<JUNCTION>」を表示するために使用します。
クロエ

16

答えではありませんが、コメントするのに十分な担当者がいません。

MS-DOSシステム上の当時の巨大な500MB FAT16ディスクでこの問題を修正したことがあります。DOSデバッグを使用して、ディレクトリテーブルを手動でダンプおよび解析しました。次に、再帰ディレクトリを削除済みとしてマークするために1ビット反転しました。DettmanとWyattの「DOS Programmers」リファレンスのコピーは、私に方法を示しました。

私はこれを非常に誇りに思っています。FAT32またはNTFSボリューム上でこのようなパワーを備えた汎用ツールがある場合、私は驚き、恐れます。当時は人生がよりシンプルでした。


8
私はあなたがこれを正当に誇りに思っていると言うでしょう。
mfinni

3
+1の担当者がいます。いい解決策。
クリスソーントン

3
これで、回答の最初の文を削除できます。
-AL

これは答えではありません。これは、異なるオペレーティングシステムと異なるファイルシステムに関する物語です。この問題(NT、NTFS)の助けにはならないことに加えて、実際には詳細が含まれていないため、同じ問題(DOS、FAT16)の人も助けにはなりません。
アンドリューメディコ

@Andrew Medico:私はあなたに同意するので、私の最初の文です。しかし、わずかに関連する問題を解決するための情報の場所を教えてくれます。
リチャード

8

Javaは長いファイルパスにも対応できます。そして、それも非常に速くできます。このコード(Java APIドキュメントからコピーしたもの)は、約1秒で(Windows 7、Java 8.0の場合)1600レベルの深さのディレクトリ構造を削除します。実際には再帰を使用しないため、スタックオーバーフローのリスクはありません。

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;

public class DeleteDir {

  static void deleteDirRecur(Path dir) throws IOException {
    Files.walkFileTree(dir, 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 e)
             throws IOException
         {
             if (e == null) {
                 Files.delete(dir);
                 return FileVisitResult.CONTINUE;
             } else {
                 throw e;
             }
         }
     });
  }

  public static void main(String[] args) throws IOException {
    deleteDirRecur(Paths.get("C:/Storage/Folder1"));
  }
}

3
大嫌い。あなたは私にJavaの使用を含む答えを支持するように強制しました、そして今、私はすべてが汚いと感じます。私はシャワーを必要とします。
HopelessN00b

謝罪いたします。最終的にあなたのトラウマから回復することを願っています。しかし、Microsoft(c#)によって開発された言語は本当にはるかに優れていますか?
SpiderPig

5
私は最近、主にWindowsの男なので、はい、そうです。私はまた、雇用主の環境のほぼ1,000のクライアントで5つの特定の異なるバージョンのJREを維持する必要があるため、Javaに対して苦い思いをするかもしれません。 ...ええと、私たちがビジネスに不可欠なアプリケーションに使用する「enterprise-y」ソフトウェアスイート。
HopelessN00b

6

chdirディレクトリに移動し、への相対パスを使用する場合、長いパス名は必要ありませんrmdir

または、POSIXシェルがインストールされている場合、またはこれを同等のDOSに移植する場合:

# untested code, didn't bother actually testing since the OP already solved the problem.

while [ -d Folder1 ]; do
    mv Folder1/Folder1/Folder1/Folder1  tmp # repeat more times to work in larger batches
    rm -r Folder1     # remove the first several levels remaining after moving the main tree out
    # then repeat to end up with the remaining big tree under the original name
    mv tmp/Folder1/Folder1/.../Folder1 Folder1 
    rm -r tmp
done

(ループ条件のために名前を変更した場所を追跡するためにシェル変数を使用することは、私がそこで行ったようにループを展開する他の選択肢です。)

これにより、KenDのソリューションのCPUオーバーヘッドが回避されます。これによりn、新しいレベルが追加されるたびにOSがツリーを上から次のレベルに移動し、アクセス許可などがチェックsum(1, n) = n * (n-1) / 2 = O(n^2)されます。O(n)Windowsが親ディレクトリの名前を変更するときにツリーをトラバースする必要がない限り、チェーンの先頭からチャンクを切り落とすソリューションはである必要があります。(Linux / Unixはサポートしていません。)OSがすべてをチェックする必要がない場合chdir、ツリーの最下部までの相対パスを使用して、chdirバックアップ時にディレクトリを削除するソリューションもO(n)必要です。どこかでCDを作成しているときに何かをするときは、すべてのシステムコールの親ディレクトリ。

find Folder1 -depth -execdir rmdir {} +最も深いディレクトリにCDを作成している間にrmdirを実行します。または、実際には、findの-deleteオプションはディレクトリで機能し、を意味し-depthます。したがってfind Folder1 -delete、まったく同じことを行う必要がありますが、より高速です。ええ、LinuxでのGNU findは、ディレクトリをスキャンrmdirし、相対パスで、次に相対パスで、次にchdir("..")。昇順ではディレクトリを再スキャンしないため、O(n)RAM を消費します。

これは実際には近似値でした。strace実際に、、およびを使用しunlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR)、多数の呼び出しが混在していることを示しています。ただし、findの実行中にディレクトリツリーが変更されない場合、効果は同じです。open("..", O_DIRECTORY|...)fchdir(the fd from opening the directory)fstat

編集:ちょうどキックのために、私はGNU / Linux(Ubuntu 14.10、2.4GHzの第一世代Core2Duo CPU、WD 2.5TB Green Powerドライブ(WD25EZRS)上のXFSファイルシステム)でこれを試しました。

time mkdir -p $(perl -e 'print "annoyingfoldername/" x 2000, "\n"')

real    0m1.141s
user    0m0.005s
sys     0m0.052s

find annoyingfoldername/ | wc
   2000    2000 38019001  # 2k lines / 2k words / 38M characters of text


ll -R annoyingfoldername
... eventually
ls: cannot access ./annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername: File name too long
total 0
?????????? ? ? ? ?            ? annoyingfoldername

time find annoyingfoldername -delete

real    0m0.054s
user    0m0.004s
sys     0m0.049s

# about the same for normal rm -r,
# which also didn't fail due to long path names

(mkdir -pは、ディレクトリと不足しているパスコンポーネントを作成します)。

はい、2k rmdir操作の場合、実際には0.05秒です。xfsは、メタデータの操作を10年前のように遅くしていたため、ジャーナルでメタデータ操作をまとめてバッチ処理するのに非常に優れています。

ext4では、作成は0m0.279秒かかり、検索で削除は0m0.074秒かかりました。


好奇心が強くなり、Linuxで試してみました。標準のGNUツールは、長いパスでも問題ありません。巨大な長いパスを使用してシステムコールを実行しようとする代わりに、ツリー内を再帰するためです。コマンドラインで38kパスを渡すとmkdirでも問題ありません!
ピーターコーデス

0

いくつかのJavaアプリケーションが行った5000以上のディレクトリディープフォルダーの混乱で同じ問題に遭遇し、このフォルダーを削除するのに役立つプログラムを作成しました。ソースコード全体はこのリンクにあります:

https://imanolbarba.net/gitlab/imanol/DiREKT

しばらくしてすべてが削除されましたが、なんとか仕事をすることができました。同じようにイライラする問題に直面する人々を助けることを願っています


リンクのみの回答は投稿しないでください。リンクから最も重要な情報を投稿自体に入れ、参照用のリンクを提供する必要があります。
フレデリックニールセン

申し訳ありませんが、それはプログラムであり、ここにすべてのソースコードを投稿したくありませんでした... プログラムを作成し、このリンクに従ってホストしていることは非常に明確だと思います。答えは、それはかなり私にはそのないリンクだけ答え、nonthelessをクリアに見えるので、私はそれがこの問題を解決するために実行されることを意図したソフトウェアであること(より明確に)を指定します
ImanolバルバSabariego

0

私もこれをスタンドアロンのWindows 10システムで持っていました。C:\ User \ Name \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Repeatは一見無限に見えます。

Windowsまたはコマンドプロンプトを使用して、約50番目までナビゲートできました。削除したりクリックしたりできませんでした。

Cは私の言語であるため、最終的にはシステムコールのループを含むプログラムを作成し、失敗するまで繰り返します。ただし、DOSバッチでも、任意の言語でこれを行うことができます。tmpというディレクトリを作成し、Repeat \ Repeatをその中に移動し、空になったRepeatフォルダーを削除し、tmp \ Repeatを現在のフォルダーに戻しました。何回も!

 while (times<2000)
 {
  ChkSystem("move Repeat\\Repeat tmp");
  ChkSystem("rd Repeat");
  ChkSystem("move tmp\\Repeat Repeat");
  ++times;
  printf("Removed %d nested so far.\n", times);
 }

ChkSystemはsystem()呼び出しを実行し、戻り値を確認し、失敗した場合は停止します。

重要なことは、何度も失敗したことです。私のプログラムはおそらく機能していないか、結局は無限に長いと思いました。ただし、システムコールを使用してこれを行ったことがありますが、同期が取れていないため、プログラムを再度実行し、中断したところから続行しました。プログラムが機能していないとすぐに考えないでください。そのため、合計で約20回実行した後、すべてをクリアしました。元々合計で約1280フォルダーの深さでした。何が原因かわかりません。クレイジー。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.