The process cannot access the file because it is being used by another process at deletion

13.6k views Asked by At

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

3

There are 3 answers

0
Mixxiphoid On BEST ANSWER

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();
                }
            }
3
Neil_M On

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.

3
Chris Shain On

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.