简体   繁体   中英

System.IO.IOException: The process cannot access the file '.txt' because it is being used by another process

I am using the next code to log errors of an web application.

using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{                
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));      

}

Sometimes, the following exception 'System.IO.IOException: The process cannot access the file '.txt' because it is being used by another process.' is thrown.

I think this is caused by multiple instances of the web app at the same time. Can you help me fix this problem, please ?

EDIT: I have to add that for every method I log like this:

Date - Method X started.

Date - Exception.Message (table not found or other errors)

Date - Method X stopped.

and when this Error appears, it's logged only this:

Date - System.IO.IOException: The process cannot access the file '.txt' because it is being used by another process.

Sadly Windows does not allow waiting on a file lock. In order to get around this all your applications will have to create a lock that all the processes involved can check.

The use of this code will only prevent threads within a single process from accessing the file:

/* Suitable for a single process but fails with multiple processes */
private static object lockObj = new Object();
lock (lockObj)
{
    using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
    {                
        myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));      
    }
}

In order to lock across multiple processes a Mutex lock is required. This gives a name to the lock that other processes can check for. It works like this:

/* Suitable for multiple processes on the same machine but fails for
   multiple processes on multiple machines */
using (Mutex myMutex = new Mutex(true, "Some name that is unlikly to clash with other mutextes", bool))
{
    myMutex.WaitOne();
    try
    {
        using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
        {
            myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
        }
    }
    finally
    {
        myMutex.ReleaseMutex();
    }

}

I don't think Mutexes can be access from remote machines so if you have a file on a file share and you are trying to write to it from processes on multiple machines then you are probably better off writing a server component on the machine that hosts the file to mediate between the processes.

Assuming you need each thread to eventually write to the log, you could lock the critical section

private static object fileLock = new Object();
...
lock (fileLock)
{
    using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
    {                
        myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));      

    }
}

This means only 1 thread at any given time can be writing to the file, other threads are blocked until the current thread has exited the critical section (at which point the file lock will have been removed).

One thing to note here is that lock works per process , therefore if your site is running the context of a web farm/garden then you would need to look at a system -wide locking mechanism ie Mutexes .

Your web server will run requests in multiple threads. If two or more requests have to log exceptions at the same time, this will lead to the exception you see.

You could either lock the section as James proposed, or you could use a logging framework that will handle multithreading issues for you, for example Lgo4net or NLog .

I've added this code to my class:

 public static bool IsFileLocked(FileInfo file)
        {
            FileStream stream = null;

            try
            {
                stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }
            catch
            {
                return true;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }

            return false;
        }

and now my LogToFile method is like this:

while (IsFileLocked(fi))
            {
            }

            using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
            {
                if (displayTime == true)
                    myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10}{3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
                else
                    myStream.WriteLine(string.Format("{0, -70}{1, -10}{2} ", guid, StringEnum.GetStringValue(enumMsg), sText));                
            }

I hope this will work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM