为什么File.Open如此昂贵?

3

我有以下代码:

try
{
    string fileName = imageQueue.Dequeue();
    FileStream fileStream = File.Open(
        fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
    Bitmap bitmap = new Bitmap(fileStream);
    Image picture = (Image)bitmap;
    pb.Tag = fileName;
    pb.Image = picture;
    return true;
}
catch (Exception ex)
{
    errorCount++;
    //If another PC has this image open it will error
    return false;
}

因为这个程序在两台PC上访问同一个文件夹以获取文件,所以当一个文件被打开时,它会抛出异常并继续移动到列表中的下一个文件。
当我同时在两台PC上打开应用程序时,第一台PC可以打开图像,但第二台无法打开。我在屏幕上同时显示了4张图像,但调试显示第二台PC在打开4个文件后需要10.5秒才能找到可以打开的文件。
为什么这么耗费时间,我该怎么做才能加快速度?
更新:我给它独占访问权限,因为我希望应用程序显示唯一的图像,所以PC1显示图像1、2、3、4,PC显示5、6、7、8,因为它无法访问1、2、3、4。我在完成使用后尽可能晚地释放文件流,以防止其他应用程序尝试打开它。

1
你需要以ReadWrite访问权限打开文件吗?如果不需要,请考虑使用Read访问权限打开它们,然后更改FileShare枚举以使用Read。http://msdn.microsoft.com/en-us/library/system.io.fileshare.aspx - Brian Dishaw
2
此外,考虑将 FileStream fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); 包装在 using ( ) { } 块中,以帮助尽快释放资源。 - Brian Dishaw
1
2.6秒打开一个被锁定的文件失败是过于长时间了。这一定是环境问题。很难猜测那可能是什么。 - Hans Passant
你真的不想把文件流作为互斥锁的方法,因为它会给你带来意外的结果,比如第二个任务在打开文件之前等待10.5秒...尝试使用控制文件(或数据库表),每个进程都可以读取以查找另一个进程正在做什么,并写入告诉另一个进程允许什么。 - Patrick
@Patrick 那真的有帮助吗?你如何避免竞争条件? - David Heffernan
4个回答

4
您正在以FileAccess.ReadWrite的方式打开文件(似乎您不打算写入)。您告诉它您不想共享该文件,FileShare.None(因此第一个获取该文件的电脑获胜)。
另外,您从未关闭流。因此,首先获取该文件的电脑将一直持有该文件,直到垃圾收集器为您关闭流。当您获取流时,请将其包装在using块中,以便文件会自动关闭:
using (FileStream fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
{
    // Do stuff with the filestream
}
// The stream will be closed when the closing brace is passed.

我不能让第二台电脑显示与第一台相同,因此我会给它独占式访问权限。完成后,我会稍后关闭文件流。 - Jon

3

修改后

如果您希望将它们锁定,可以考虑使用轻量级数据库(如sqllite、xml等)来标记文件为“正在使用”。然后在方法中检查它是否正在使用。这将消除在尝试打开已锁定文件时等待File.Open超时的情况。

原始内容

我想我应该回答而不是评论......

try
{
    string fileName = imageQueue.Dequeue();
    using( FileStream fileStream = File.Open( fileName, FileMode.Open, FileAccess.Read, FileShare.Read) )
    {
        Bitmap bitmap = new Bitmap(fileStream);
        Image picture = (Image)bitmap;
        pb.Tag = fileName;
        pb.Image = picture;
    }

    return true;
}
catch (Exception ex)
{
    errorCount++;
    //If another PC has this image open it will error
    return false;
}

该应用程序轮询一个目录以查找新文件,因此它需要进行插入操作,并在文件未引发异常的情况下更新列以表示其正在使用,这样才能避免时间问题。 - Jon
在 process1 打开文件之前,您需要检查文件是否正在使用中,然后更新数据库以表示该文件正在使用中(如果 process2 同时声明了相同的文件,则此操作需要优雅地失败),然后 process1 可以开始使用该文件。 - Patrick

3

我不能确定地回答,但我的最佳建议是系统中的某些东西,无论是在.net框架类还是文件系统中,都在实施一种超时/重试机制,以防文件共享失败。这可以解释你报告的异常延迟。


我不能让第二台电脑显示与第一台相同,因此我会给它独占访问权限。 - Jon
请在您的问题中添加该细节。 - David Heffernan
我需要独占访问权限,以防止其他应用程序打开同一文件。每个应用程序实例需要从同一文件夹中显示唯一的图像。 - Jon
@Jon,我现在明白你的问题了,你看过我的更新答案了吗? - David Heffernan
是的,但你说要将FileShare更改为读取,以便其他进程可以读取文件。我不想这样做。 - Jon
@Jon 不,我是说在你告诉我们你在做什么之前改变 FileShare。请重新阅读答案,并注意最后4段已被划掉。 - David Heffernan

0

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