【问题标题】:How can I unlock a FileStream lock?如何解锁 FileStream 锁?
【发布时间】:2012-04-30 03:22:50
【问题描述】:

我正在实现一个模块,以将文件从客户端机器分块上传到服务器。在服务器端,我使用的是 WCF Soap 服务。

为了分块上传文件,我已经从 Microsoft http://msdn.microsoft.com/en-us/library/aa717050.aspx 实现了这个示例。我已经能够让它在一个简单的场景中工作,所以它确实以块的形式上传文件。这个分块模块正在使用 WSDualHttpBinding。

我需要实现一个功能来重新上传文件,以防在上传特定文件时上传过程因任何原因(用户选择、机器关闭等)而停止。

在我的 WCF 服务中,我有一个方法可以在服务器端处理文件写入:

public void UploadFile(RemoteFileInfo request)
{
FileInfo fi = new FileInfo(Path.Combine(Utils.StorePath(), request.FileName));

if (!fi.Directory.Exists)
{
    fi.Directory.Create();
}

FileStream file = new FileStream(fi.FullName, FileMode.Create, FileAccess.Write);
int count;
byte[] buffer = new byte[4096];
while ((count = request.FileByteStream.Read(buffer, 0, buffer.Length)) > 0)
{
    file.Write(buffer, 0, count);
    file.Flush();
}
request.FileByteStream.Close();
file.Position = 0;
file.Close();

if (request.FileByteStream != null)
{
    request.FileByteStream.Close();
    request.FileByteStream.Dispose();
}
}

块模块正在发送块,而函数 request.FileByteStream.Read(buffer, 0, buffer.Length) 正在被消耗。

文件流初始化后,文件被锁定(这是初始化文件流以进行写入时的正常行为),但我遇到的问题是我在发送/接收过程执行时停止了上传过程,然后分块模块使用的通道不会被取消,因此文件保持锁定,因为 WCF 服务仍在等待发送更多数据,直到发送超时到期(超时为 1 小时,因为我需要上传文件 +2.5GB )。在下一次上传时,如果我尝试上传相同的文件,WCF 服务会出现异常,因为无法为相同的文件再次初始化文件流。

我想知道是否有办法避免/删除文件锁定,所以在下一次运行时我可以重新上传同一个文件,即使之前的文件流已经锁定了文件。

任何帮助将不胜感激,谢谢。

【问题讨论】:

  • FileStream.Unlock 在这里有用吗?
  • 您可以尝试使用 FileStream 构造函数并将 SharingMode 参数设置为 System.IO.FileShare.ReadWrite。
  • 我已经尝试过 FileStream.Unlock,但它并没有解决问题,因为该文件在之前的 WCF 调用中被之前的进程锁定了。

标签: wcf wcf-binding .net


【解决方案1】:

我个人不喜欢这种解决方案。保持连接并不理想。

使用您的示例,您可能会完成 2.5GB 文件的一半,并且该过程可能会中止。您最终会遇到上述情况。更糟糕的是,您需要重新提交所有已经提交的数据。

我会自己处理块并将它们附加到同一个文件服务器端。调用指示文件正在启动的 WCF 方法,以块的形式上传数据,然后在上传完成时调用另一个方法。如果您确信文件名是唯一的,那么您甚至可以通过单个方法调用来完成此操作。

类似:

ulong StartFile(string filename) // This returns the data already uploaded
void UploadFile(string filename, ulong start, byte[] data)
void EndFile(string filename) // Just as a safety net

如果您不想走我上面概述的路线(它不会直接回答您的问题),则上述问题的一个简单解决方案是在上传时使用临时文件名,然后重命名上传完成后的文件。无论如何,您确实应该采用这种方法来防止服务器上的应用程序在上传完成之前获取文件。

【讨论】: