Search code examples
c#file-ioprocessfilestream

How can I prevent my file from being used by another process?


This is a sequel to the question here where I was wondering why my stream was not fordable.

Utilizing ideas from some of the cats who answered the other question, I've now got this code:

private readonly FileStream _fileStream;
private readonly StreamWriter _streamWriter;

. . .

private ExceptionLoggingService()
{
    const int MAX_LINES_DESIRED = 1000;
    int linesInLogFile;

    string uriPath = GetExecutionFolder() + "\\Application.log";
    string logPath = new Uri(uriPath).LocalPath;
    _fileStream = File.Open(logPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    StreamReader _streamReader = new StreamReader(_fileStream);
    List<String> logList = new List<String>();

    while (!_streamReader.EndOfStream)
    {
        logList.Add(_streamReader.ReadLine());
    }
    linesInLogFile = logList.Count;
    while (logList.Count > MAX_LINES_DESIRED)
    {
        logList.RemoveAt(0);
    }

    if (linesInLogFile > MAX_LINES_DESIRED)
    {
        _fileStream.Close();
        File.Delete(logPath);
        File.Create(logPath);
        _fileStream.Close(); // added this; did not help
        _fileStream.Dispose(); // this also did no good
        _fileStream = File.OpenWrite(logPath); // <= exception occurs here
    }

    _streamWriter = new StreamWriter(_fileStream);

    foreach (String s in logList)
    {
        _streamWriter.WriteLine(s);
    }
    _streamWriter.Flush(); // here is okay, right (as opposed to within the foreach loop)?
}

...but on the indicated ("OpenWrite()") line I get the following exception (I added the two lines above it, first the call to Close(), then Dispose(), but the exception remains the same):

System.IO.IOException was unhandled
  _HResult=-2147024864
  _message=The process cannot access the file 'C:\HoldingTank\Sandbox\bin\Debug\Application.log' because it is being used by another process.

So if Close doesn't close _fileStream, and Dispose doesn't dispose it, what can be done?

UPDATE

This doesn't strictly answer my question, but it works, inspired by Lloyd's comment:

const int MAX_FILESIZE_ALLOWED = 20000;
string uriPath = GetExecutionFolder() + "\\Application.log";
string logPath = new Uri(uriPath).LocalPath;
FileInfo f = new FileInfo(logPath);
long fileLenInBytes = f.Length;
if (fileLenInBytes > MAX_FILESIZE_ALLOWED)
{
    File.Delete(logPath);
}
_fileStream = File.OpenWrite(logPath);
_streamWriter = new StreamWriter(_fileStream);

Solution

  • You can use one of the FileShare enumeration, for example:

    _fileStream = File.Open(logPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
    

    You can use FileShare.None to lock the file, as described on MSDN:

    Declines sharing of the current file. Any request to open the file (by this process or another process) will fail until the file is closed.

    However, because this is logging I'd advise you to use something like NLog or Log4Net rather than rolling you own, let that deal with log output.