FileStream.Close()没有立即关闭文件句柄

我正在以块的forms阅读源文件并将其传递给WCf服务以记录在一些远程SMB上。 我一直打开FileStream,直到写完所有数据。

打开和关闭文件处理多次降低性能,所以我遵循这种方法。

写完所有数据后,我调用CloseHandle()。 然后我可能需要通过调用DoSomeOperation()对同一文件执行一些其他操作。 因为我在CloseHandle()函数中关闭了文件句柄,但是我在DoSomeOperation()中得到了“文件正在与其他进程一起使用”的错误。 如果我在延迟一段时间之后调用DoSomeOperation(),那么问题就不存在了。

当我调用FileStream.Close()时,请帮助我们立即关闭文件句柄。

这段代码片段是大型程序的一部分,所以我不能在这里提及所有代码。

//In WCF service FileStream fs = null; public void AppendBytes(string fileName, byte[] data, long position) { try { if (fs==null)//In first call, open the file handle fs = System.IO.File.Open(fileName, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.None); fs.Write(data, 0, data.Length); } catch (Exception ex) { //Close handle in case of error if (fs != null) fs.Close(); } } public void CloseHandle() { //Close handle explicitly if (fs != null) fs.Close(); } public void DoSomeOperation(string fileName) { using (FileStream fsO = System.IO.File.Open(fileName, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.None)) { //Do something with file here, this is atomic operation so I am opening FileStream with 'using' to dispose at operation is over } } //In client public void CallerFunction() { //Read Data from sourceFile in chunk and copy to target file using WCF.AppendBytes on another machine WCF.AppendBytes(filename, data, pos); WCF.CloseHandle(); WCF.DoSomeOperation(filename); //I get error here that file is in use with some other process. if I put a thread.sleep(1000) just before this statement then all works fine. } 

我编写了一个小的测试代码来重现控制台应用程序上的相同场景:只需从Main()调用TestHandleClose(),它会在一些周期后给出错误。

  static void TestHandleClose() { int i = 0; try { if (File.Exists(@"d:\destination\file2.exe")) File.Delete(@"d:\destination\file2.exe"); byte[] data = null; int blocksize = 10 * 1024 * 1024; for( i=0;i<100;i++) { using (FileStream fr = File.Open(@"d:\destination\File1.zip", FileMode.Open, FileAccess.Read, FileShare.None)) { data = new byte[blocksize]; fr.Read(data, 0, blocksize); //We are reading the file single time but appending same data to target file multiple time. using (FileStream f = File.Open(@"d:\destination\file2.exe", FileMode.Append, FileAccess.Write, FileShare.None)) { f.Write(data, 0, data.Length); //We are writing same data multiple times. f.Flush(); f.Close(); } } } if (File.Exists(@"d:\destination\file2.exe")) File.Delete(@"d:\destination\file2.exe"); } catch (Exception ex) { throw; } } 

最后的示例代码有帮助,我很确定我有你的问题。

问题是,即使最新的示例代码也无法重现。 但是,它显示了您可能错过的另一件事 – 您正在编写的文件是.exe 。 为什么这是个问题? 好吧,有几个原因,但其中一个原因是当你列出.exe文件使用资源管理器的目录时,资源管理器继续尝试读取它(获取图标)。 在这么短的时间内,无法使用FileShare.None打开FileShare.None (事实上​​, FileShare.Read可能也无济于事,因为很可能无论谁打开它都没有指定FileShare.ReadWrite )。

再一次, FileStream关闭得很好,并且运行良好(尽管摆脱了FlushClose调用 – 它们浪费了性能,并且没用)。 问题是另一个进程在此期间尝试读取该文件。 它可能是我的情况下的一些文件管理器(Explorer,Total Commander,…),它可能是某些FileSystemWatcher ,它可能是一个病毒扫描程序(虽然现在大多数病毒扫描程序使用卷影副本),它可能是自动为图像等创建缩略图的东西。但是你自己发布的代码根本不会导致问题 – 这是其他人抓住你的文件。

您基本上有两个选项 – 要么在您需要的时候保持文件打开,要么将IOException视为临时,并在给定的时间间隔内重试几次。 这就是你应该做的事情,而不是依赖于快乐的道路 – 大多数读者只允许并发读取,而不是写入。

就我而言,缺少FileShare模式。 我曾经在很短的时间内从同一个文件中的多个源读/写。 有时它传递良好,有时它被阻止(另一个进程持有文件),即使文件流已被释放,我正在使用一个锁和一个using()。 当我添加FileShare模式ReadWrite时,一切都解决了。


 using (FileStream fileStream = new FileStream(file, mode, access, FileShare.ReadWrite)) {...