即使之前关闭了文件,另一个进程也会使用该文件

时间:2013-06-10 03:33:53

标签: c# .net exception-handling filesystemwatcher

我不明白为什么相同的代码在32位系统上成功运行,但尝试在64位系统上运行它总是会出错:

  

另一个进程正在使用的文件

我声明文件观察者事件以观察文件已更改。

我的代码类似于以下内容:

static void Main()
{
   //init load file
   LoadAssembly(dll);

   //bind watching event.
   FileSystemWatcher watcher = new FileSystemWatcher(rootPath, "*.dll");
   watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite;
   watcher.Changed += new FileSystemEventHandler(TemplateFile_Changed);
   watcher.IncludeSubdirectories = false;
   watcher.EnableRaisingEvents = true;
}

private LoadAssembly(assemblyFile)
{
    try
    {
        using (FileStream fs = new FileStream(assemblyFile, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            //read a file and write to memorystream.
            ......
            fs.Close();
            fs.Dispose();
        }
        asm = Assembly.Load(ms.ToArray());
    }
    finally
    {
        ms.Close();
    }
}

private void TemplateFile_Changed(object sender, FileSystemEventArgs e)
{
    lock (_sync)
    {              
         LoadAssembly(e.FullPath);           
    }            
}

我测试可以在32位系统中工作的代码(在我的计算机中)。当我部署到64位系统时,当我更改文件并告诉应用程序需要重新加载此文件时,总是得到一个

  

另一个进程使用的文件`

using (FileStream fs = new FileStream(assemblyFile, FileMode.Open, FileAccess.Read, FileShare.Read))

更新-1

好吧,谢谢@Hans Passant回答,这个异常是由文件观察者发起的,它触发了一个已更改的事件并仍保持文件打开状态。我在TemplateFile_Changed中添加一个Thread.Sleep()看起来解决了这个问题。

private void TemplateFile_Changed(object sender, FileSystemEventArgs e)
{
    lock (_sync)
    {      
         Thread.Sleep(2000);
         LoadAssembly(e.FullPath);           
    }            
}

2 个答案:

答案 0 :(得分:3)

当您使用using时,您无需关闭Stream,因为它会在Stream之后自动关闭using;所以试试这段代码:

 using (FileStream fs = new FileStream(assemblyFile, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        //read a file and write to memorystream.
    }

答案 1 :(得分:0)

您需要处理此异常,这对您的应用程序来说绝对是正常情况。想象一下,某些应用程序获取文件的独占权并修改它 - 您将获得相同的异常。但是你无能为力 - 只需等待应用程序释放文件。

在异常处理程序中,您可能会将这些未成功加载的程序集放到某个集合中,并尝试稍后处理它(例如,通过计时器)。

此外,您的应用程序可能更好的架构不能在文件更改时完全加载程序集。将其置于队列中,对组进行更改并定期加载。您将避免不必要的加载(在多次更改的情况下)并从文件系统事件处理中拆分加载逻辑。