1

I thought I solved this problem by closing and disposing my reader, but still in some cases the file was in use. Next I called the Garbage Collector, so the file will be released. This solves 99% of all the issues which will bring up this error. Code used:

 public override void Finish() { // Kill the reader! if (_reader != null) { _reader.Close(); _reader.Dispose(); // Make sure the server doesn't hold the file GC.Collect(); } DeleteFile(); } 

Finish is called after a big process which will handle the file's content.

When I process a file with only 1 (or very few) line I sometimes get this error. It seems windows is to quick and DeleteFile(); fails. It is very hard for me to reproduce this error, but sometimes it just happens twice in a row.
This never occurs when I process a file with takes more then 2 seconds to process.
I cannot use a using because files can be GB's, and windows doesn't like it when its memory is getting too full. Also, this way the process performs way better.

Question:
Is there anything else I can do to prevent this error?

PS: Feel free to ask for more information.

EDIT:
Code to delete a file

 protected void DeleteFile() { // Delete the file if (FileName != null && File.Exists(FileName)) File.Delete(FileName); } 

Code to create the file

 protected void WriteFile() { // Prepare variables string path = Path.GetTempPath(); path += "\\MyTempFile"; // Modifiy path to avoid overwriting an existing file. path += ".csv"; // Write the file to the temp folder using (FileStream fs = new FileStream(path, FileMode.Create)) { fs.Write(MyFile, 0, MyFile.Length); } // Was the writing successfully completed? _FileName = File.Exists(path) ? path : null; } 

Code to create the reader

 protected override void ReadFile() { if (FileName == null) WriteFile(); // Read the lines _reader = new StreamReader(FileName, Encoding.Default, true); while (_reader.Peek() != -1) { TotalRows++; _reader.ReadLine(); } // Read the lines _reader = new StreamReader(FileName, Encoding.Default, true); } 

I use an abstract class to determine how the input should be read. With the following statement I'll loop through the content of the file.

 while (FileReader.NextRow(out currentRow, out currentRowNumber)) { // Process current Row... } 

The method NextRow() Looks like this

 public override bool NextRow(out List<object> nextRow, out int rowNumber) { if (RowNumber > TotalRows) { nextRow = null; rowNumber = 0; return false; } // Set the row number to return rowNumber = RowNumber; // Prepare the row nextRow = _reader.ReadLine().ExtensionThatProcessesTheRow(); RowNumber++; return true; } 

After the while loop closes I call the finish process. FileReader.Finish();

8
  • 5
    You do NOT need to call GC.Collect. You shouldn't, and it should have no impact on the ability to delete your file. Commented May 31, 2012 at 14:01
  • 2
    What does the code that accesses a file look like? We could make better suggestions there if we could see it. Commented May 31, 2012 at 14:02
  • 2
    We'd need to see all of the code that you are using to create, interact with, and delete these files. Chances are you are leaking an object somewhere, or that two threads are simultaneously interacting with the same file. Commented May 31, 2012 at 14:03
  • @ChrisShain If I were leaking an object, I think the error should be consequent. Isn't it possible that a virusscanner/indexer/whatever is holding the file locked for deletion? Commented May 31, 2012 at 15:34
  • @Joe Would you please explain why I shouldn't call GC.Collect? Commented May 31, 2012 at 15:36

3 Answers 3

1

As you are saying it only happens sometimes it may just be that the lock is held onto and that if you do a check then hopefully if it fails by the time you get round to doing another check on it then it should have had the time to get rid of the cached lock. If you use a method like this to check if the file is still being used:

public bool CheckIfFileIsBeingUsed(string fileName){ try{ File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None); } catch (Exception exp){ return true; } return false; 

}

And if it returns false then go ahead and delete the file, other wise wait and then run the check again.

Sign up to request clarification or add additional context in comments.

3 Comments

That could mean that I get stuck in a loop and isn't safe. While(FileIsInUse) { Thread.Sleep(100)} <-- Could make the computer wait for a very long long time. I did consider this ;).
You could always make it into a do while loop and add a counter that breaks the loop after so many attempts and posts out a user friendly error saying the file was locked.
hmmm. I will give it a try, thanks for the tip. I will come back to this.
0

Note: This should probably be a comment, but I need the additional space.

This code doesn't make sense:

// Prepare variables string path = Path.GetTempPath(); // Write the file to the temp folder using (FileStream fs = new FileStream(path, FileMode.Create)) 

Path is the directory for temporary files. You shouldn't be able to create a file with that name.

Additionally, here you use a variable called FileName:

protected void DeleteFile() { // Delete the file if (FileName != null && File.Exists(FileName)) File.Delete(FileName); } 

but in WriteFile you are using a variable called _FileName:

// Was the writing successfully completed? _FileName = File.Exists(path) ? path : null; 

My guess, based on the above, is that you are not writing what you think you are writing, or not deleting what you think that you are deleting.

3 Comments

Believe me this works :P... As I said I work with abstract classes. the _FileName is the private property where FileName is the public property.
What is the value of the variable path after calling string path = Path.GetTempPath(); above? The documentation specifically states that this "Returns the path of the current user's temporary folder." msdn.microsoft.com/en-us/library/…
I edited my question. I saw I forgot to copy some lines of code. I make it a .csv and add a (n) to make sure the filename is unique.
0

I think I found the problem...
this reader wasn't disposed before reseting it in ReadFile().

 _reader = new StreamReader(FileName, Encoding.Default, true); while (_reader.Peek() != -1) { TotalRows++; _reader.ReadLine(); } 

I changed it to.

 using (var reader = new StreamReader(FileName, Encoding.Default, detectEncodingFromByteOrderMarks: true)) { while (reader.Peek() != -1) { TotalRows++; reader.ReadLine(); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.