(Görünüşe göre) sonsuz özyinelemeli bir klasörü kaldırma


46

Her nasılsa, eski Server 2008 (R2 değil) kutularından biri, görünüşte sonsuz tekrarlanan bir klasör geliştirdi. Yedekleme aracısı klasöre tekrar girmeye çalıştığında ve asla geri dönmediğinden, bu bizim yedeklemelerimizle kötü oynuyor.

Klasör yapısı şuna benzer:

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

... ve bunun gibi. 90'lı yıllarda hep birlikte oynadığımız Mandelbrot setlerinden biri gibi .

Denedim:

  • Explorer'dan silmek. Evet, iyimserim.
  • RMDIR C:\Storage\Folder1 /Q/S - bu döner The directory is not empty
  • ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE - Bu robocopy.exe çökmeden önce birkaç dakika boyunca klasörler arasında döner.

Birisi bu klasörü iyice öldürmenin bir yolunu önerebilir mi?


1
Bunun /MIRyerine denerdim : ROBOCOPY /MIR C:\temp\EmptyDirectory C:\Storage\Folder1aynı zamanda chkdsksadece kıkırdamalar için koşmaya değer olabilir .
jscott

1
/MIRdaha uzun sürecek gibiydi, fakat sonunda da bombalandı (“robokopi çalışmayı durdurdu”). Biraz yapmaktan korkuyorum chkdsk; bu oldukça eski bir sunucudur ve bu sorunun daha büyük dosya sistemi sorunlarının göstergesi olduğundan endişeliyim ...
KenDub

7
Bir Linux (Ubuntu / Centos / Fedora / ...) masaüstü deneme CD'sinden önyüklemeyi ve klasörü oradan çıkarmayı deneyin.
Guntram Blohm

2
@KenD Dosya sistemindeki bozulma sorunlarından şüpheleniyorsanız, öncelikle dosya sistemini onarmayı denemelisiniz. Dizin kaldırma işlemlerini denemek işleri daha da kötüleştirebilir.
jscott

1
Çünkü (aşağıdaki cevabınızdan), dizin sonsuz değildi, sadece çok derindi, eğer CygWin ya da UnxUtils kuruluysa, findderinlikli bir ilk dizini kaldırmak için kullanabilirsiniz:find Storage/Folder1 -depth -exec rmdir {} \;
Johnny

Yanıtlar:


45

Yararlı tavsiyeler için herkese teşekkürler.

StackOverflow bölgesine doğru giderken, bu C # kod pasajını çözerek sorunu çözdüm. Uzun dosya yollarına erişen sorunları özellikle ele alan Delimon.Win32.IO kütüphanesini kullanır .

Sırf bunun başkasına yardım etmesi durumunda, işte kod - bu, bir şekilde sıkışıp kaldığım ~ 1600 tekrarlama seviyesinden geçti ve hepsini kaldırmak için yaklaşık 20 dakika sürdü.

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
Ben .Delete(normal System.IOsürüm yerine) Delimon sürümünü kullanarak bile denedim ve bir istisna atmasa da , hiçbir şey yapmıyor gibiydi. Kesinlikle yukarıdaki yöntemi kullanarak özyineleme yaş aldı ve .Deletesadece 5-10 saniye boyunca şeyler çiğnendi. Belki bir kaç dizinde paramparça oldu ve sonra pes etti?
KenD

4
Bunun nasıl başladığını hiç düşündün mü? Bazı kötü yazılmış kullanıcı programı programının suçu gibi geliyor.
Parthian Shot

8
1600 kez bir fonksiyona tekrar mı giriyorsunuz? Gerçekten yığın taşması bölgesi!
Aleksandr Dubinsky,

2
Bir yana, klasörler herhangi bir şey tarafından dolduruldu mu? Ne aralıklarla belirleyebilirse özyinelemeli klasörleri oluşturulan ve çarpma recursions sayısına göre, (umarım) ... Bu sorunun başladığı kaba bir zaman aralığı alacak
Get-HomeByFiveOClock

8
Vay, bunu çözdüğüne sevindim. Bilginize, resmi Microsoft bu tür bir durum için desteklenen destek "hacim yeniden biçimlendirmek" dir. Evet, cidden. : /
UmutsuzN00b

25

Özyinelemeli bir bağlantı noktası olabilir. Böyle bir şey Sysinternalsjunction bir dosya ve disk yardımcı programı ile oluşturulabilir .

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

Ve şimdi c: \ Hello \ Hello \ Hello .... (MAX_PATH ulaşana kadar çoğu komut için 260, ancak bazı Windows API işlevleri için 32.767 karakter).

Bir dizin listesi bunun bir kavşak olduğunu gösterir:

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:\>

Bağlantı yardımcı programını kullanmak silmek için:

junction -d c:\Hello\Hello

4
Ne yazık ki, DIRsadece bana düz ole dizinleri gösterir - korktuğum hiçbir kavşak belirtisi yok
KenD

2
Çifte kontrol yapabilir misiniz junction -s C:\Storage\Folder1 ?
Brian,

3
No reparse points found:(
KenD

3
Gerçek bir alt dizin karışıklığını neyin yarattığını merak ediyorum.
Brian,

2
dir /aBelirli bir ad belirtmeden '<JUNCTION>' görmek için kullanın .
Chloe,

16

Cevap değil, yorum yapmak için yeterli temsilcim yok.

Bir keresinde MS-DOS sistemindeki 500 MB'lık bir FAT16 diskte bu sorunu çözdüm. DOS dizinini manuel olarak boşaltmak ve dizin tablosundan ayrıştırmak için kullandım. Özyinelemeli dizini silinmiş olarak işaretlemek için bir bit çevirdim. Dettman ve Wyatt'ın 'DOS Programcıları' Referansı kopyasını bana yol gösterdi.

Hala bununla gurur duyuyorum. FAT32 veya NTFS hacimleri üzerinde böyle bir güce sahip herhangi bir genel amaçlı araç varsa, hayret ve korkardım. O zamanlar hayat daha basitti.


8
Bununla haklı olarak gurur duyduğunu söyleyebilirim .
mfinni

3
+1 benden bazı haklar var. Güzel çözüm.
Chris Thornton

3
Artık cevabınızın ilk cümlesini silebilirsiniz.
AL,

Bu bir cevap değil. Farklı bir işletim sistemi ve farklı bir dosya sistemi hakkında bir hikaye. Bu (NT, NTFS) sorunu için hiçbir yardımın olmamasına ek olarak, aslında herhangi bir ayrıntı içermediğinden, aynı problemi olan birisine (DOS, FAT16) bile yardım etmeyecektir.
Andrew Medico

@Andrew Medico: Size katılıyorum, bu yüzden ilk cümle. Fakat size biraz ilgili problemi çözmek için bilgiyi nerede bulacağınızı söylüyorum.
Richard,

8

Java ayrıca uzun dosya yollarıyla da ilgilenebilir. Ve bunu da çok daha hızlı yapabilir. Bu Java kodu (Java API belgelerinden kopyaladım), 1600 seviyeli bir derin dizin yapısını yaklaşık 1 saniyede (Windows 7, Java 8.0 altında) siler ve aslında yineleme kullanmadığından yığın taşması riski olmadan.

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
Senden nefret ediyorum. Beni Java kullanarak yapılan bir cevabı yükseltmeye zorladın ve şimdi de kendimi kirli hissediyorum. Duşa ihtiyacım var.
UmutsuzN00b

Özür dilerim. Umarım sonunda travmalarından kurtulursun. Ancak Microsoft (c #) tarafından geliştirilen bir dil gerçekten çok daha iyi mi?
SpiderPig

5
Ben öncelikle bu günlerde Windows'luyum, yani evet, evet. Ayrıca, işveren ortamımdaki yaklaşık 1000 müşteriye 5 özel, farklı JRE sürümü bulundurmak zorunda kaldığı için, bunlardan biri 2009’a dayanan, kötü niyetli, kötü amaçlı yazılımlar yüzünden Java’ya karşı acı ve önyargılı olabilirim. ... iş için kritik uygulamalar için kullandığımız "enterprise-y" yazılımıdır.
UmutsuzN00b

6

chdirDizine girerseniz ve sadece göreli yolları kullanıyorsanız uzun yol adlarına ihtiyacınız yoktur rmdir.

Ya da yüklü bir POSIX kabuğunuz varsa ya da bunu DOS muadiline bağladığınızda:

# 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

(Döngü koşulu olarak yeniden adlandırdığınız yeri izlemek için bir kabuk değişkeni kullanmak, orada yaptığım gibi döngüyü açmanın diğer alternatifidir.)

Bu, işletim sistemini nyeni bir seviye eklendiğinde her seferinde ağacı yukarıdan yukarı seviyeye geçmeye zorlayan ve izinleri kontrol eden vb . İşlem yapan KenD'in çözümünün CPU ek yükünden kaçınır sum(1, n) = n * (n-1) / 2 = O(n^2). Zincirin başından itibaren bir yığıntan ayrılan çözümler, O(n)Windows'un üst dizinini yeniden adlandırırken bir ağaçtan geçiş yapması gerekmediği sürece olmalıdır . (Linux / Unix yapmaz.) chdirAğacın dibine kadar tüm yolların ve oradan göreceli yolları kullanan çözümler, dizinleri chdiryedekledikçe kaldırarak O(n), işletim sisteminin tüm denetlemenizi kontrol etmesi gerekmediğini düşünerek CD'leri bir yere yazarken bir şeyler yaptığınızda her sistem üst dizinini çağırır.

find Folder1 -depth -execdir rmdir {} +rmdir'i çalıştırırken en derin dizine CD yazacak. Veya aslında, find'in -deleteseçeneği dizinlerde çalışır ve ima eder -depth. Öyleyse find Folder1 -deleteaynı şeyi yapmalı, ama daha hızlı. Evet, GNU Linux'ta bir dizini tarayarak, göreceli yollarla alt dizinlere, sonra rmdirda göreceli yolla CD'leri bularak bulur chdir(".."). Yükselirken dizinleri yeniden taramaz, bu yüzden O(n)RAM tüketir .

: Bu gerçekten bir yaklaşım oldu straceo ASLINDA kullandığı gösterileri unlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR), open("..", O_DIRECTORY|...)ve fchdir(the fd from opening the directory)bir grup ile, fstatçok karışık çağrılar. Ancak, dizin çalışırken ağaç çalışırken değiştirilmiyorsa, efekt aynıdır.

düzenleme: Sadece başladı, bunu GNU / Linux'ta denedim (Ubuntu 14.10, 2.4GHz birinci nesil Core2Duo CPU'da, WD 2.5TB Yeşil Güç sürücüsündeki (WD25EZRS) bir XFS dosya sisteminde).

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, bir dizin ve eksik yol bileşenleri oluşturur).

Evet, 2k rmdir ops için gerçekten 0.05 saniye. xfs, meta veri işlemlerinin 10 yıl önceki gibi yavaş olmalarını sağladığı için dergide meta veri işlemlerini bir araya getirmede oldukça iyidir.

Ext4'te create 0m0.279s aldı, find ile sil hala 0m0.074s aldı.


merak ettim ve Linux'ta denedim. Standart GNU araçlarının uzun yollarla gayet iyi olduğu anlaşılıyor, çünkü dev uzun yollarla sistem çağrısı yapmak yerine ağacı tekrar kapatıyorlar. Komut satırında 38k yolunu geçtiğinizde mkdir bile gayet iyi!
Peter Cordes

0

Bazı Java uygulamalarının yaptığı 5000'den fazla dizin derinlemesine klasör karışıklığıyla aynı sorunu yaşadım ve bu klasörü kaldırmanıza yardımcı olacak bir program yazdım. Kaynak kodun tamamı bu bağlantıda:

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

Bir süre sonra her şeyi sildi, ancak işi yapmayı başardı, umarım (benim gibi) aynı sinir bozucu mesele ile karşılaşan insanlara yardım eder.


Lütfen sadece link cevaplarını göndermeyin. En önemli bilgiyi yazının içindeki linkten yazmalı ve referans için link vermelisiniz.
Frederik Nielsen

Özür Oh, bir program ve gerçekten burada TÜM kaynak kodunu yayınlamak istemedim ... Bence oldukça açık ben ve ben bu bağlantıyı takip kendisini barındıran ediyorum bir program ve motivasyon yazdığını ve tüm içindedir cevap, bu yüzden bana çok net görünüyor ki, sadece bir bağlantı değil, yine de, (daha açık bir şekilde) bu sorunu çözmek için çalıştırılması gereken bir yazılım olduğunu belirleyeceğim
Imanol Barba Sabariego

0

Ben de, bağımsız bir Windows 10 sisteminde olsa da vardı. C: \ Kullanıcı \ Adı \ Tekrarla \ Tekrarla \ Tekrarla \ Tekrarla \ Tekrarla \ Tekrarla \ Tekrarla \ Tekrarla \ Yinelenen görünüşte tekrarla.

Windows ya da Komut İstemi'ni kullanarak yaklaşık 50'nci dolana kadar gezinebilirim. Silemedim, tıklayamadım, vb.

C benim dilim bu yüzden sonunda başarısız olana kadar tekrar eden, sistem çağrıları döngüsüne sahip bir program yazdım. DOS toplu olsa bile, herhangi bir dilde bunu yapabilirsiniz. Tmp adında bir dizin hazırladım ve içine Repeat \ Repeat 'i taşıdım, şimdi boş olan Repeat klasörünü sildim ve tmp \ Repeat'i tekrar geçerli klasöre taşıdım. Tekrar tekrar!

 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 sadece bir sistem () çağrısı yapar ve başarısız olursa durdurma değerini döndürür.

Önemli olarak, birkaç kez başarısız oldu. Belki de programımın işe yaramadığını ya da sonuçta çok uzun sürdüğünü düşündüm. Ancak bunu daha önce sistem çağrılarıyla, işler senkronize edilmeyecek şekilde yapmıştım, bu yüzden programı yeniden başlattım ve kaldığı yerden devam ettim, bu yüzden hemen programınızın çalışmadığını düşünmeyin. Toplamda, yaklaşık 20 kez çalıştırdıktan sonra, hepsini temizledi. Toplamda, başlangıçta yaklaşık 1280 klasör vardı. Buna neyin sebep olduğu hakkında hiçbir fikrim yok. Çılgın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.