在.NET中使用FileStream保存文件后立即解锁?

10

我有这段代码可以保存PDF文件。

FileStream fs = new FileStream(SaveLocation, FileMode.Create);
fs.Write(result.DocumentBytes, 0, result.DocumentBytes.Length);
fs.Flush();
fs.Close();

它工作得很好。但是有时它不能立即释放锁,这会导致在运行此函数之后运行的函数出现文件锁定异常。

是否有一种理想的方法可以在 fs.Close() 之后立即释放文件锁?


1
文件是在本地硬盘上还是网络共享上?你是否安装了任何防病毒软件? - Ian Mercer
6个回答

17

以下是理想情况:

using (var fs = new FileStream(SaveLocation, FileMode.Create))
{
    fs.Write(result.DocumentBytes, 0, result.DocumentBytes.Length);
}

大致相当于:

FileStream fs =  null;
try
{
    fs = new FileStream(SaveLocation, FileMode.Create);
    fs.Write(result.DocumentBytes, 0, result.DocumentBytes.Length);
}
finally
{
    if (fs != null)
    {
        ((IDisposable)fs).Dispose();
    }
}

使用using更易读。


更新:

@aron,现在我在思考。

File.WriteAllBytes(SaveLocation, result.DocumentBytes);

看起来甚至比理想情况更美丽 :-)


9
这是一个很好的using语句的示例,但由于它与楼主的代码最终等效,所以并没有解答提出的问题。 - Jeffrey L Whitledge
3
@Jeffrey,我知道我喝了很多啤酒,但我真的不明白这跟原帖的代码有什么等价关系。 - Darin Dimitrov
5
Dispose调用Close。Close调用Flush。最终结果是相同的。你的更改有益于避免在异常或早期返回的情况下意外保持文件打开状态,但它不会使文件锁更快地被解除。 - Jeffrey L Whitledge
3
这段代码在基本功能方面与之等效。然而,它在垃圾回收处理方面有根本性的不同...这是问题所在。+1 - NotMe
7
@Chris Lively - Close()方法会释放非托管资源。无论哪种情况,垃圾回收都将完全相同。此问题与垃圾回收无关。 - Jeffrey L Whitledge
显示剩余3条评论

5

我们在生产中使用()语句包裹时也遇到了同样的问题。

其中一个最常见的罪魁祸首是反病毒软件,它可能在文件关闭后悄悄地进入并抓取文件以检查是否包含病毒,然后再释放它。

但即使所有反病毒软件都不参与,对于存储在网络共享上的极高负载系统,我们仍然偶尔会遇到这个问题。在关闭文件后稍微让线程“睡眠”一下似乎可以解决这个问题。如果有更好的解决方法,我很愿意听听!


很难推荐一个具体的值,因为它将取决于许多因素;从小开始,比如说10。 - Ian Mercer

3
我无法想象在文件关闭后锁定的原因。但您应该考虑将其封装在using语句中,以确保即使出现异常,文件也会被关闭。
using (FileStream fs = new FileStream(SaveLocation, FileMode.Create))
{
  fs.Write(result.DocumentBytes, 0, result.DocumentBytes.Length);  
}

3

如果此函数后续运行的功能属于同一应用程序,则更好的方法是在整个过程开始时以读/写方式打开文件,然后将文件传递给每个函数,直到进程结束前不关闭它。这样,应用程序就不需要阻塞等待IO操作完成。


1

当我使用.Flush()时,这对我有用。我不得不在using语句内部添加一个close。

 using (var imageFile = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite,FileShare.ReadWrite))
 {
     imageFile.Write(bytes, 0, bytes.Length);
     imageFile.Flush();
     imageFile.Close();
  }

当我在using中使用WhiteAsync时,我也不得不做同样的事情。 - codenamezero

0

当我关闭一个FileStream并立即在另一个类中打开文件时,遇到了同样的问题。使用语句不是解决方案,因为FileStream已经在另一个地方创建并存储在列表中。清除列表是不够的。

看起来需要垃圾收集器释放流才能重新使用文件。如果关闭和打开之间的时间太短,可以使用

GC.Collect();

在关闭流之后立即这样做,这对我有用。

我猜Ian Mercer的解决方案将线程置于休眠状态可能会产生相同的效果,让垃圾回收机制有时间释放资源。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接