2015-04-29 76 views
3

我正在使用下一个代码来记录Web应用程序的错误。System.IO.IOException:进程无法访问文件'.txt',因为它正在被另一个进程使用

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:该进程无法访问该文件“因为它正由另一个进程使用” .TXT被抛出。

我认为这是由web应用程序的多个实例同时引起的。你能帮我解决这个问题吗?

编辑:我要补充的是,我每次登录这样的方法:

日期 - 方法X开始。

日期 - Exception.Message(找不到表或其他错误)

日期 - 方法X停止。

而且出现这个错误时,系统也只会记录本:

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

回答

-1

我已经添加了此代码我的课:

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

我希望这会工作。

+0

它可能会改善情况,但它并没有完全解决它。原因是另一个进程可能在调用IsFileLocked和创建StreamWriter之间打开文件。 –

+0

您可能会遇到的另一个问题是,在非常高的负载下,一个线程可能会阻塞另一个线程。这是因为没有队列来确保等待的线程最终能够看到。线程可以释放对文件的锁定并在另一个线程的检查之间进行请求。另外,因为这是在每次尝试之间暂停轮询文件时,等待的线程可能会使用大量的CPU。 –

3

假设你需要每个线程最终写入日志,你可以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工作每个进程,因此,如果您的网站上运行的Web农场/花园的背景下,那么你就需要看一个系统 - 宽锁定机制,即Mutexes

+0

问题在于,Web服务器倾向于在多个进程以及多个线程中运行网站。这里给出的锁只适用于一个进程。 –

+0

@MartinBrown“* web服务器倾向于在多个进程中运行网站*” - 只有在网络农场/花园的上下文中运行。这是一个有效的观点,但考虑到OP没有提到任何有关跑步的事情,我认为它们不是。 – James

+0

他们在回收过程中也这样做。旧流程和新流程之间存在重叠,而旧流程完成了开始回收之前开始的请求。 –

4

不幸的是,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(); 
    } 

}

我不认为互斥可以从远程计算机访问,因此,如果你有一个文件共享上的文件和你正试图从进程写它那么你可能最好在托管文件的机器上编写一个服务器组件,以在这些进程之间进行调解。

3

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

您可以按照James的建议锁定该部分,也可以使用日志框架来处理多线程问题,例如Lgo4netNLog

+0

Web服务器可能会在多个进程以及多个线程中运行该站点。无论是在网络花园的情况下,还是在回收过程中都需要一段时间。 –

相关问题