4

I am trying to parse a folder and delete all the files in it.

DirectoryInfo dir = new DirectoryInfo("C\\Temp");
if (dir.GetDirectories().Any(p => p.Name == "\\NewTemp"))
{
    foreach (string file in Directory.GetFiles(dir + "\\NewTemp"))
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }
}

This code works fine and deletes all the files in my \NewTemp Folder. But if any of the files is opened those files will not be deleted. I want to forecfully close the files that are opened and delete them. I even tried

foreach (string file in Directory.GetFiles(dir + "\\NewTemp"))
{
    TextReader tr = new StreamReader(dir+"\\NewTemp\\"+file);
    tr.Close();
    File.SetAttributes(file, FileAttributes.Normal);
    File.Delete(file);
}

But no use. Please let me know where I am missing.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Sneha S Murthy
  • 141
  • 1
  • 2
  • 11
  • I'm pretty sure there's this command line utility that you can use to get all the processes that have a particular file open, and I'm also pretty sure you can taskkill those processes from c# – Sam I am says Reinstate Monica Oct 04 '12 at 14:42
  • tr is trying to close the file TextReader tr = new StreamReader(file). I have made a typo – Sneha S Murthy Oct 04 '12 at 14:43
  • http://stackoverflow.com/questions/177146/how-do-i-get-the-list-of-open-file-handles-by-process-in-c It's not too simple with managed code. In this answer there is a link to a proget on Codeproject that can help you. – 2GDev Oct 04 '12 at 14:43

6 Answers6

5

Please let me know where I am missing.

Well you're closing your handle on the file - but that's not going to affect any other file handles, whether they're owned by your process or not. Basically you can't delete a file which is in use elsewhere, unless it's been explicitly opened with a file share flag which allows it to be deleted. That's just the way the Windows file systems work, as far as I know. (EDIT: I originally suggested using Notepad as a way of keeping a file handle open, but apparently it closes the handle after loading it into memory. Um, try other apps :)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Well, actually you can delete file that you opened in notepad from the explorer. It's all depends on the FileShare that you open the file with... so, sometimes you can delete files that are in use elsewhere. it's all depends which FileShare level the app that opened the file needed. – Shahar Gvirtz Oct 04 '12 at 14:43
  • I believe you can force close file handles (any file handle), I've used programs that do it. I don't think there are any .Net functions to do it, so you might have to dig into the windows API for an answer. – Kratz Oct 04 '12 at 14:43
  • 1
    That's actually a bad example. NotePad reads the file and then closes it. You can delete files opened with NotePad without closing NotePad first. – Devin Burke Oct 04 '12 at 14:43
  • 1
    Notepad example was incorrect. Notepad doesn't keep handle open. It loads all text in memory and releases the handle. You can delete the file even when Notepad is open. – loopedcode Oct 04 '12 at 14:45
  • 2
    @Kratz: That's a highly non-trivial task. You need to somehow get the processes that hold a handle to the file and make those processes close that handle. There is no single WinAPI function for that. – Daniel Hilgarth Oct 04 '12 at 15:08
1

You cannot delete a file if handle is open by another process. You will have to kill that process first before you can delete the file.

You can look at this example to see how to find all open handles.

loopedcode
  • 4,863
  • 1
  • 21
  • 21
0

This is a handy tool for finding which process has file handles:

http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

Justin Harvey
  • 14,446
  • 2
  • 27
  • 30
0

If you know what program has your file open, you can just taskkill that program directly, and then delete your file.

If you don't know what process has your file open, than you can use a utility like this, and then process the output. I myself would redirect the output and then use regex to find what process I want to get, but there's probably a better way.

Bear in mind that this method is not entirely safe, and can kill processes that you ight not want to kill.

Community
  • 1
  • 1
0

These are your options, in the order in which you should try them (from least invasive to very invasive).

  1. Do what you are currently doing (remove the read-only attribute and try to delete the file).
  2. You can try to rename the file, then delete it.
  3. If that doesn't work, then you should open the file with the FILE_FLAG_DELETE_ON_CLOSE flag (pinvoke out to CreateFile). When all the other handles to the files are closed the system will delete the file for you.
  4. If the above call to CreateFile fails because the file isn't opened with FILE_SHARE_DELETE, then you should call MoveFileEx with the MOVEFILE_DELAY_UNTIL_REBOOT flag (and the lpNewFileName parameter set to NULL / IntPtr.Zero). This will cause the file to be deleted on the next restart/reboot of the system.
  5. If step 4 isn't practical (i.e. you cannot wait for a reboot), only then should to proceed down the route of killing off random processes which may have the file locked. Just keep in mind that this can lead to system instability, especially if it is a System process that you are trying to kill.
josh poley
  • 7,236
  • 1
  • 25
  • 25
0
foreach (System.Diagnostics.Process myProc in System.Diagnostics.Process.GetProcesses())
{
    if (myProc.ProcessName == "EXCEL")
    {
        myProc.Kill();
        break;
    }
}
Milo
  • 3,365
  • 9
  • 30
  • 44