Frage

Ich brauche ein Verzeichnis zu löschen, die schreibgeschützte Dateien enthält. Welcher Ansatz ist besser:

  • Mit DirectoryInfo.Delete(), oder,

  • ManagementObject.InvokeMethod("Delete")?

Mit DirectoryInfo.Delete() muß ich manuell für jede Datei des Schreibschutz-Attribut deaktivieren, aber ManagementObject.InvokeMethod("Delete") scheint nicht zu brauchen. Gibt es eine Situation, wo man mehr bevorzugt auf die andere ist?

Beispielcode (test.txt ist nur lesen).

Erste Möglichkeit:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");
File.SetAttributes(@"C:\Users\David\Desktop\Test\test.txt", FileAttributes.Archive);
test.Delete(true);

Zweiter Weg:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");

string folder = @"C:\Users\David\Desktop\Test";
string dirObject = "Win32_Directory.Name='" + folder + "'";
using (ManagementObject managementObject = new ManagementObject(dirObject))
{
    managementObject.Get();
    ManagementBaseObject outParams = managementObject.InvokeMethod("Delete", null,
    null);
    // ReturnValue should be 0, else failure
    if (Convert.ToInt32(outParams.Properties["ReturnValue"].Value) != 0)
    {
    }
}
War es hilfreich?

Lösung

Hier ist eine Erweiterung Methode, die Attributes rekursiv auf Normal setzt, löscht dann die Elemente:

public static void DeleteReadOnly(this FileSystemInfo fileSystemInfo)
{
    var directoryInfo = fileSystemInfo as DirectoryInfo;    
    if (directoryInfo != null)
    {
        foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos())
        {
            childInfo.DeleteReadOnly();
        }
    }

    fileSystemInfo.Attributes = FileAttributes.Normal;
    fileSystemInfo.Delete();
}

Andere Tipps

einfachste Weg, rekursive Aufrufe zu vermeiden, ist durch die AllDirectories Option nutzen, wenn FileSystemInfos bekommt, etwa so:

public static void ForceDeleteDirectory(string path) 
{
    var directory = new DirectoryInfo(path) { Attributes = FileAttributes.Normal };

    foreach (var info in directory.GetFileSystemInfos("*", SearchOption.AllDirectories))
    {
        info.Attributes = FileAttributes.Normal;
    }

    directory.Delete(true);
}

Versuchen Sie dies,

private void DeleteRecursiveFolder(string pFolderPath)
{
    foreach (string Folder in Directory.GetDirectories(pFolderPath))
    {
        DeleteRecursiveFolder(Folder);
    }

    foreach (string file in Directory.GetFiles(pFolderPath))
    {
        var pPath = Path.Combine(pFolderPath, file);
        FileInfo fi = new FileInfo(pPath);
        File.SetAttributes(pPath, FileAttributes.Normal);
        File.Delete(file);
    }

    Directory.Delete(pFolderPath);
}

Eine andere Methode, ohne die Notwendigkeit einer Rekursion.

public static void ForceDeleteDirectory(string path)
{
    DirectoryInfo root;
    Stack<DirectoryInfo> fols;
    DirectoryInfo fol;
    fols = new Stack<DirectoryInfo>();
    root = new DirectoryInfo(path);
    fols.Push(root);
    while (fols.Count > 0)
    {
        fol = fols.Pop();
        fol.Attributes = fol.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
        foreach (DirectoryInfo d in fol.GetDirectories())
        {
            fols.Push(d);
        }
        foreach (FileInfo f in fol.GetFiles())
        {
            f.Attributes = f.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
            f.Delete();
        }
    }
    root.Delete(true);
}
private void DeleteRecursiveFolder(DirectoryInfo dirInfo)
{
    foreach (var subDir in dirInfo.GetDirectories())
    {
        DeleteRecursiveFolder(subDir);
    }

    foreach (var file in dirInfo.GetFiles())
    {
        file.Attributes=FileAttributes.Normal;
        file.Delete();
    }

    dirInfo.Delete();
}

Die beste Lösung ist es, alle Dateien zu markieren, als nur nicht lesen, und dann das Verzeichnis löschen.

// delete/clear hidden attribute
File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.Hidden);

// delete/clear archive and read only attributes
File.SetAttributes(filePath, File.GetAttributes(filePath) 
    & ~(FileAttributes.Archive | FileAttributes.ReadOnly));

Beachten Sie, dass ~ ist eine bitweise logische Operator, der die Ergänzung des gegebenen binären Wert zurückgibt. Ich habe nicht getestet, aber es sollte funktionieren.

Danke!

Ich würde sagen, dass Ihr erster Ansatz deutlicher und lesbar aussieht. Die zweite Methode riecht wie Reflexion, geben Sie ist nicht sicher und sieht seltsam. Die ManagementObject können mehrere Dinge darstellen, so ist es nicht offensichtlich, dass .InvokeMethod("Delete") löscht tatsächlich ein Verzeichnis.

Die Sache, die Ich mag nicht über den ersten Ansatz (Directory.Delete) ist der Fall, wo es Verzeichnisse sind, die auch schreibgeschützte Dateien enthalten, und sie haben Verzeichnisse, die schreibgeschützt sind auch Dateien usw. auf. Es scheint, wie Sie für jede Datei in dem Verzeichnis und alle Unterverzeichnisse rekursiv aus, dass die Flagge drehen müßten.

Mit dem zweiten Ansatz können Sie löschen, genau das erste Verzeichnis, und es prüft nicht, ob die Dateien schreibgeschützt sind. Dies ist jedoch das erste Mal, dass ich WMI in C # verwendet haben, so bin ich nicht so zufrieden mit ihm. Also ich bin nicht sicher, wenn sie mit dem WMI-Ansatz für andere Anwendungen zu gehen, anstatt nur die System.IO Methoden verwenden.

An der Oberfläche scheint die WMI-Ansatz effizienter als über das gesamte Dateisystem Iterieren (nehmen zum Beispiel das Verzeichnis hat 10 von Tausenden von Dateien). Aber ich weiß nicht, dass WMI auch Iterationen nicht tun. Ist dies der Fall, näher an das Metall zu sein (wiederum Annahmen) soll es effizienter sein.

Für Eleganz, verursacht ich die rekursive Methode ist cool.

Performance-Tests sollten die Effizienz Frage beantworten. Und kann entweder elegant sein, wenn in einem Verlängerungsverfahren Directory gewickelt.

Hier ist eine andere Lösung, die Rekursion auf sich selbst vermeidet.

public static void DirectoryDeleteAll(string directoryPath)
{
    var rootInfo = new DirectoryInfo(directoryPath) { Attributes = FileAttributes.Normal };
    foreach (var fileInfo in rootInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    foreach (var subDirectory in Directory.GetDirectories(directoryPath, "*", SearchOption.AllDirectories))
    {
        var subInfo = new DirectoryInfo(subDirectory) { Attributes = FileAttributes.Normal };
        foreach (var fileInfo in subInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    }
    Directory.Delete(directoryPath, true);
}

Dies wird durch Neueinstellungen Attribute, auf die Ordner und Dateien vor dem Löschen, so konnte man nur die letzte Zeile für eine ‚DirectoryResetAttributes‘ Methode entfernen und verwenden löschen getrennt.

Auf einem verwandten beachten, während diese arbeitete, hatte ich Probleme dann mit Pfaden zu löschen, die ‚zu lang‘ waren und am Ende mit einer Robocopy Lösung hier gepostet: C # Löschen eines Ordners, lange Wege

Um Follow-up auf Vitaliy Ulantikov Lösung ich es mit einem Umbenennungs / verschieben Ordner Methode ergänzt haben:

  public static void renameFolder(String sourcePath, String targetPath) {
     try
     {
        if (System.IO.Directory.Exists(targetPath))
           DeleteFileSystemInfo(new DirectoryInfo(targetPath));
        System.IO.Directory.Move(sourcePath, targetPath);
     }
     catch (Exception ex)
     {
        Console.WriteLine("renameFolder: " + sourcePath + " " + targetPath + " " + ex.Message);
        throw ex;
     }
  }

  private static void DeleteFileSystemInfo(FileSystemInfo fsi) {
     fsi.Attributes = FileAttributes.Normal;
     var di = fsi as DirectoryInfo;

     if (di != null)
     {
        foreach (var dirInfo in di.GetFileSystemInfos())
        {
           DeleteFileSystemInfo(dirInfo);
        }
     }

     fsi.Delete();
  }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top