user2729292
user2729292

Reputation:

File remains locked after stream is closed

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).

Upvotes: 4

Views: 2652

Answers (1)

rkawano
rkawano

Reputation: 2503

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.

Upvotes: 1

Related Questions