2

I'm having problems with renaming a directory multiple times, it seems to lock the file.

// e comes from a objectListView item
DirectoryInfo di = (DirectoryInfo)e.RowObject;
DirectoryInfo parent = Directory.GetParent(di.FullName);
String newPath = Path.Combine(parent.FullName, e.NewValue.ToString());

// rename to some temp name, to help change lower and uppercast names
di.MoveTo(newPath + "__renameTemp__");
di.MoveTo(newPath);

// Trying to cleanup to prevent directory locking, doesn't work...
di = null;
parent = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

Any help is much appreciated, because the first rename works okay, but when trying to do a new rename on the renamed folder, it throws an exception :

The process cannot access the file because it is being used by another process. A first chance exception of type 'System.IO.IOException' occurred in mscorlib.dll

So first time rename that folder works, second time throws exception, I'm guessing the application holds a lock on the new folder, but how to work around it? I should be able to rename a folder twice right?

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
JHN
  • 1,018
  • 9
  • 12
  • Can you let us know what the values of e.RowObject and e.NewValue are when you run this and get the exception please? – Rob Levine Mar 15 '11 at 15:25
  • e.NewValue is what gets returned after the cell has been edited, so any string will do. RowObject is an DirectoryInfo stored as an object cast back into an DirectoryInfo, that's how ObjectListView control stores it's values. I think the focus should be on the locking and disposing of objects holding a reference to the path. I checked all other values and they return okay. – JHN Mar 15 '11 at 15:38
  • Did you try `Directory.Move(di.FullName, newPath);` – Aidiakapi Mar 15 '11 at 15:45
  • Yes, just did, same result, first rename routine works just fine, second time I invoke the handler the code is part, it throws the is being used exception. No virusscanner or nothing, closing and starting the program again allows me to rename it again, but only 1 time. – JHN Mar 15 '11 at 16:00
  • Have a look at my updated answer. The suggestion of Aidiakapi was a good one, you just might not have removed all occurrences of DirectoryInfo from your code. – Daniel Hilgarth Mar 15 '11 at 16:15

3 Answers3

10

Introduction

To reproduce your problem, I created the following method:

private static string RenameFolder(string path, string newFolderName)
{
    DirectoryInfo di = new DirectoryInfo(path);
    DirectoryInfo parent = Directory.GetParent(di.FullName);
    String newPath = Path.Combine(parent.FullName, newFolderName);

    // rename to some temp name, to help change lower and uppercast names
    di.MoveTo(newPath + "__renameTemp__");
    di.MoveTo(newPath);

    return di.FullName;
}

When I call it like the following, it works:

var path = @"C:\Temp\test";
var newPath = RenameFolder(path, "TESt");
newPath = RenameFolder(path, "Test1");

When I call it like the following, it doesn't work:

var path = @"C:\Temp\test";
var newPath = RenameFolder(path, "TESt");
newPath = RenameFolder(newPath, "Test1");

The only difference between the two calls is, that in the first version I pass in the original name, i.e. everything in lower case. In the second case, I supply the new name, i.e. everything in uppercase except the last letter. Even sleeping for 20 seconds in between the two calls to RenameFolder doesn't change that. Odd!

Solution

If I implement RenameFolder like this, it works in both cases:

private static string RenameFolder(string path, string newFolderName)
{
    String newPath = Path.Combine(Path.GetDirectoryName(path), newFolderName);

    // rename to some temp name, to help change lower and uppercast names
    Directory.Move(path, newPath + "__renameTemp__");
    Directory.Move(newPath + "__renameTemp__", newPath);

    return newPath;
}

Somehow, DirectoryInfo seems to have a case sensitive lock on the path.

Explanation
I have none, maybe someone with a little bit more insight into the internal ways of DirectoryInfo can shed some light on this strange behavior.

Important point
Don't use GC.Collect if you don't know, what you are doing! Normally, you don't need to call this method.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Very good, do *not* use GC.Collect, unless you know what you're doing. And for my part, I guess the directory is in use by another program? Try closing it before using it again. – Aidiakapi Mar 15 '11 at 15:28
  • I know GC is something to be used with caution, but I'm out of ideas. I don't have a virus scanner or anything like that on my machine. Doesn't matter on which directory I run it, every second time no luck, restart application, works again. – JHN Mar 15 '11 at 15:33
  • @JHN: Did you try my suggestion with the sleep in between the two moves? – Daniel Hilgarth Mar 15 '11 at 15:35
  • @Daniel, yes just did a System.Threading.Thread.Sleep(500); and same behaviour. I'm going to try to take it out into a simple app, and see if locking still occurs. – JHN Mar 15 '11 at 15:43
  • @JHN: Just to clarify something: Is the second call to `MoveTo` in your code above throwing the exception? Or is the complete code you posted running fine the first time but not the second time? – Daniel Hilgarth Mar 15 '11 at 15:45
  • @Daniel, exactly, the first time everything runs just fine, renaming works as expected, no exceptions are thrown. Then when I try to rename the (now renamed) folder again, it throws a : `A first chance exception of type 'System.IO.IOException' occurred in mscorlib.dll` `The process cannot access the file because it is being used by another process.` – JHN Mar 15 '11 at 15:58
  • @JHN: Then my suggestion with the sleep doesn't make sense. I update my answer to show you the code I am using. I also provided a solution! – Daniel Hilgarth Mar 15 '11 at 16:13
  • Working on it now, will report back! Thanks so much for all the efforts so far! – JHN Mar 15 '11 at 16:52
  • That's it, it worked! Thanks ever so much, I will digest everything and see if I can fully comprehend everything you've said. Thanks! – JHN Mar 15 '11 at 16:57
1

My previous answers were wrong. As mentioned in the comments, the MoveTo() method updates the DirectoryInfo object to represent the new path, which isn't clearly documented.

As Daniel Hilgarth points out in his answer, the problem probably lies somewhere else. You might need to add logic which checks when the directory is accessible again.

Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161
  • -1: The first sentence in your answer is wrong. the `DirectoryInfo` instance is updated to reflect the new path after the call to `MoveTo` – Daniel Hilgarth Mar 15 '11 at 15:26
  • @Daniel: Interesting, that's a non-documented side effect. – Steven Jeuris Mar 15 '11 at 15:28
  • It might not be documented, but isn't it obvious? DirectoryInfo isn't a static class. Wouldn't you implement it just the same, if you would implement a class like this? Anything else would be unintuitive. – Daniel Hilgarth Mar 15 '11 at 15:30
  • No, I'm using the DirectoryInfo.moveTo, so after the first tempName rename, the fullname is stored back into the DirectoryInfo and the consecutive rename works just fine. Trying to rename the newly renamed folder is where the problems lies. I also spit out all Fullnames inbetween and the first run it behaves as expected. – JHN Mar 15 '11 at 15:32
  • @Daniel: I would make the method return a new DirectoryInfo. – Steven Jeuris Mar 15 '11 at 15:32
  • 1
    @Steven: That would only make sense if DirectoryInfo would be immutable, which indeed is a point worth discussing. – Daniel Hilgarth Mar 15 '11 at 15:35
  • @Steven: No need to keep a history of your wrong answers. Just remove them. – Daniel Hilgarth Mar 15 '11 at 15:42
  • @Daniel: Done. Just trying to prevent any further downvotes, while still leaving the useful information there. :) – Steven Jeuris Mar 15 '11 at 15:46
  • @Steven: That's why I asked you to change it and why I removed my downvote after you have changed it. – Daniel Hilgarth Mar 15 '11 at 15:48
1

Grab a copy of Process Monitor and see exactly what has locked that directory after your rename:

http://technet.microsoft.com/en-us/sysinternals/bb896645

NotMe
  • 87,343
  • 27
  • 171
  • 245
  • +1 for showing me that I might have misunderstood his question – Daniel Hilgarth Mar 15 '11 at 15:48
  • I don't know exactly how to get meaningful information out of proces explorer that can help solve this problem. I filter on application, I see threads getting started and exited, but nothing specific to the renaming. – JHN Mar 15 '11 at 16:04