【问题标题】:Sharing file locks共享文件锁
【发布时间】:2010-04-22 11:00:03
【问题描述】:

我目前正在开发一个文件处理服务,它查看文件共享,文件通过 FTP 上传到该文件。

为了可扩展性,我被要求使该服务能够进行负载平衡,因此该服务必须预期不同机器上的其他服务也可能会尝试处理这些文件。

好的,所以我认为我应该能够通过在处理文件之前为我的进程获取排他锁并跳过可能已经被另一个进程锁定的任何文件来实现这一点。

这种方法的关键如下所示(为简单起见,我省略了错误处理):

using(FileStream fs = File.Open(myFile, FileMode.Open, FileAccess.ReadWrite, (FileShare.Read | FileShare.Delete))
{
//Do work
}

Q1:我的进程现在锁定了这个文件。我认为这意味着我可以访问同一个文件(不使用流)并且仍然可以正确访问它,但是根据测试,我似乎只有通过流锁定的好处。这是正确的吗?

(例如,在我包含 FileShare.Delete 之前,File.Delete(myFile) 失败)

上述锁最终使用'Write'权限来确定哪个服务拥有该文件,但旨在允许其他进程仍然读取该文件。这是因为拥有锁的进程会尝试验证文件是否为有效的 zip 文件,该文件使用第三方库 (Xceed.Zip)。然而,这失败了,说文件“正在被另一个进程使用”。使用反射器我最终发现有问题的调用是:

stream = this.m_info.Open(FileMode.Open, FileAccess.Read, FileShare.Read);

现在我希望它能够工作,因为它只想读取文件,但它失败了。原因似乎在similar question 中进行了概述。但是,由于这是第 3 方 API,我无法更改他们的代码以使用 ReadWrite。

Q2:有没有办法可以正确锁定文件,使其不会被其他服务获取,但仍可以使用外部 API 将其验证为 zip 文件?

我觉得应该有一个“正确”的方法来做到这一点,但目前我能想到的最好办法是锁定文件,将其移出共享目录,然后在新的位置。

【问题讨论】:

    标签: file windows-services concurrency locking


    【解决方案1】:

    如果您打算通过处理 UnauthorizedAccessException 来被动地处理这种情况,我认为您犯了一个严重的错误。

    这可以通过主动重命名文件来解决。例如,您可以将服务配置为仅读取名称格式为“Filename.YYYYMMDD.txt”的文件。在处理文件之前,您可以将其重命名为“Filename.YYYYMMDD.processing”。然后在处理完文件后将其重命名为“Filename.YYYYMMDD.done”。

    您甚至可以通过创建另一个将文件名排队的服务来更进一步。此服务将是一个 FileSystemWatcher,用于侦听 FileAdd 操作。一旦它接收到该事件,它就会将文件名排队到全局消息队列中。然后,您的每个服务将只是将文件名出列,而不再需要担心并发访问。

    HTH

    【讨论】:

    • 被接受,因为替代解决方案是合理的。回答我自己的问题: Q1:是的。锁只针对流,不针对流程 Q2:否。必须考虑替代方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    相关资源
    最近更新 更多