views:

7005

answers:

9

I need to delete a directory that contains read-only files. Which approach is better: using DirectoryInfo.Delete(), or ManagementObject.InvokeMethod("Delete")? With DirectoryInfo.Delete, I have to manually turn off the read-only attribute for each file, but ManagementObject.InvokeMethod("Delete") doesn't appear to need to. Is there any situation where one is more preferable to the other?

Sample code (test.txt is read only).

First way:

        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);

Second way:

        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)
            {
            }
        }
+1  A: 

I would say that your first approach looks more explicit and readable. The second method smells like reflection, is not type safe and looks weird. The ManagementObject can represent multiple things, so it's not obvious that .InvokeMethod("Delete") actually deletes a directory.

Thomas Eyde
+1  A: 

The best solution is to mark all the files as non-read only, and then delete the directory.

// 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));

Notice that ~ is a Bitwise logical operator which returns the complement of the given binary value. I haven't tested this, but it should work.

Thanks!

+1  A: 

The thing that I don't like about the first approach (directory.delete) is the case where there are subdirectories that also contain read-only files, and they have subdirectories that have read-only files as well, and so on. It seems like you'd have to turn off that flag for every file in the directory and all subdirectories recursively.

With the second approach, you can just delete that first directory, and it doesn't check whether the files are read-only. However, this is the first time I've used WMI in C#, so I am not all that comfortable with it. So I am unsure when to go with the WMI approach for other applications, instead of just using the System.IO methods.

David Hodgson
+15  A: 

I wrote my own method wich sets attributes to normal for each file and directory recursively, and then deletes them:

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();
}
Veton
Cool. I hadn't even noticed the GetFileSystemInfos method before!
David Hodgson
This worked perfectly!
Dustin Venegas
This is excellent...
Andrew Flanagan
great method! thanks
Axarydax
A: 

On the surface, using the WMI approach seems more efficient than iterating over the entire file system (assume for example the directory has 10's of thousands of files). But I do not know that WMI also doesn't do iterations. If it does, being closer to the metal (again, assumptions) it should be more efficient.

For elegance, I concede the recursive method is cool.

Performance testing should answer the efficiency question. And either can be elegant if wrapped in an extension method of DirectoryInfo.

ongle
+1  A: 

Another method without the need for recursion.

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);
}
jasonk
A: 

Hope this can help

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

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

        Directory.Delete(pFolderPath);
    }
Frederic Arteau
A: 

pPath is not defined anywhere. You probably meant "file"

Anony
+1  A: 

var pPath = Path.Combine(pFolderPath, file);

Pavel