4

I have some code that is trying to read from a file that may or may not be encrypted. If it is encrypted then it has a header with a few bytes of information before the actual data. The logic to access the file is along these lines:

bool encrypted = IsEncryptedFile(fileName);
Stream s = null;

if (encrypted)
{
    s = new EncryptedStreamReader(fileName);
}
else
{
    s = new StreamReader(fileName);
}

// Read from s

On rare occasions (say, one file out of 10000), I get the error "The process cannot access the file xxx because it is being used by another process" when trying to create the stream reader. The IsEncryptedFile method opens the file to read the header (if present) and no other code accesses the file. That method always closes the file (it is opened in a using statement) and it always succeeds.

I have assumed that closing the .NET stream does not guarantee that the underlying operating system handle is closed and added code to wait and retry after an interval. This reduces the frequency with which the error occurs, but it still happens occasionally.

My questions are:

Is my assumption correct that code which closes and then immediately opens a file may receive this error because Windows is still releasing it, even though the .NET Stream.Close method call has returned (or the using block exited)?

Is there a less rubbish way of getting around this than extending my retry interval?

EDIT

IsEncryptedFile does this

private bool IsEncryptedFile(string fileName)
{
    using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        //Read header from fileStream
        //Returns true if encrypted else false
    }
}

I'm not including the actual logic for obvious reasons, but it is irrelevant anyway because all you need to know is that the stream is always closed (using statement).

There is not a multi-threading issue. There is no other part of my code accessing the file. The method is called only once for each file. It doesn't matter what happens in 'Read from s' because by that point the file has either been opened (OK - 9999 times in 10000) or not opened (bad - 1 time in 10000).

  • 5
    Are you sure the problem is not a side-effect of another process accessing your file, such as a virus killer, defragmenter, ... ? – Roy Dictus Jan 02 '14 at 14:37
  • Possibly IsEncryptedFile function works with some IDisposable class, and doesn't dispose it. See aso: `using` C# statement http://msdn.microsoft.com/en-us/library/yh598w02.aspx – Alex F Jan 02 '14 at 14:37
  • 1
    Can you post the source for IsEncryptedFile? – Original10 Jan 02 '14 at 14:39
  • What does the code for `// Read from s` look like? – Mike Perrenoud Jan 02 '14 at 14:40
  • Is your code runs multithreaded ?, unless you should post your IsEncryptedFile code here ... – Bahram Jan 02 '14 at 14:42
  • and `s` gets closed and disposed as well? – rene Jan 02 '14 at 14:44
  • There is a same question it is problem of anti-virus [1]: http://stackoverflow.com/questions/6350224/does-filestream-dispose-close-the-file-immediately – RyanWang Jan 02 '14 at 14:58
  • Roy Dictus - I don't believe so, but we are checking this out. –  Jan 02 '14 at 16:00
  • You can add another param to FileStream specifying FileShare.None. Also, you can try a Wait algorithm like [this](http://stackoverflow.com/questions/50744/wait-until-file-is-unlocked-in-net) – rkawano Jan 02 '14 at 16:30

1 Answers1

1

Make sure you are correct disposing the streams with using and try finally clauses.

Also, you can use FileStream to set file access options.

Ex.:

bool encrypted = IsEncryptedFile(fileName);
Stream s = null;
try
{
    if (encrypted)
    {
        s = new EncryptedStreamReader(fileName);
    }
    else
    {
        s = new FileStream(fileName, FileMode.Open, FileAccess.Read);
    }

    // Read from s
}
finally
{
    if (s != null)
        s.Close();
}

Check all your methods that opens streams (such IsEncryptedFile) to ensure that all streams are being closed properly.

rkawano
  • 2,443
  • 22
  • 22
  • 1
    I'd change the last line 's.Close()' to 's.Dispose()'. – Luis Filipe Jan 02 '14 at 15:03
  • According to documentation, dispose does: Releases all resources used by the System.IO.TextReader object. And Close does: Closes the System.IO.TextReader and releases any system resources associated with the TextReader. – rkawano Jan 02 '14 at 15:16
  • Dispose calls 'Close'. If the class implements IDisposable one ought to use Dispose(). If the implementer changes the internal logic and your code will not break. Don't try to second guess what dispose does by 'pasting' whatever code it implements – Luis Filipe Jan 02 '14 at 15:35
  • I pasted the documentation of the Framework about StreamReader. There are a lots of discussion about these two methods, as you can see [here](http://stackoverflow.com/questions/911408/does-stream-dispose-always-call-stream-close-and-stream-flush) [here](http://stackoverflow.com/questions/4153595/close-or-dispose) and [here](http://stackoverflow.com/questions/61092/close-and-dispose-which-to-call?lq=1) – rkawano Jan 02 '14 at 15:56
  • In the real code s is Disposed, but that is not the point. The problem is that the IO exception is thrown _before s is opened_ –  Jan 02 '14 at 16:02