System.IO.IOException: 该进程无法访问文件“.txt”,因为它正被另一个进程使用

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

我正在使用下一个代码来记录 Web 应用程序的错误。

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

}

有时会出现以下异常 'System.IO.IOException: The process cannot access the file '.txt',因为它正被另一个进程使用。'被抛出。

我认为这是由于同时有多个 Web 应用程序实例造成的。你能帮我解决这个问题吗?

编辑:我必须为我这样记录的每个方法添加它:

日期 - 方法 X 开始。

日期 - Exception.Message(table 未找到或其他错误)

日期 - 方法 X 已停止。

当这个错误出现时,它只记录这个:

日期 - System.IO.IOException: 该进程无法访问文件“.txt”,因为它正被另一个进程使用。

假设您需要每个线程最终写入日志,您可以lock临界区

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

    }
}

这意味着在任何给定时间只有 1 个线程可以写入文件,其他线程将被阻塞,直到当前线程退出临界区(此时文件锁将被移除)。

这里要注意的一件事是 lock 每个进程 工作 ,因此如果您的站点是 运行 网络上下文 farm/garden 那么您需要查看 系统 范围的锁定机制,即 Mutexes.

我已将此代码添加到我的 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;
        }

现在我的 LogToFile 方法是这样的:

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

我希望这会奏效。

遗憾的是 Windows 不允许等待文件锁定。为了解决这个问题,您的所有应用程序都必须创建一个所有相关进程都可以检查的锁。

使用此代码只会阻止单个进程中的线程访问文件:

/* 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));      
    }
}

为了跨多个进程锁定,需要互斥锁。这为其他进程可以检查的锁提供了一个名称。它是这样工作的:

/* 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();
    }

}

我不认为互斥量可以从远程机器访问,所以如果你在文件共享上有一个文件并且你试图从多台机器上的进程写入它,那么你最好编写一个服务器组件在托管文件的机器上在进程之间进行调解。

您的网络服务器将 运行 在多个线程中请求。如果两个或多个请求必须同时记录异常,这将导致您看到的异常。

您可以按照 James 的建议锁定该部分,或者您可以使用一个日志框架来为您处理多线程问题,例如 Lgo4net or NLog