文件夹重命名后,文件存在检查在UNC共享上返回不正确的值

时间:2012-03-08 08:00:08

标签: c# windows winapi file-io

在Windows 7(或服务器)框中,我们在UNC共享上有一个文件夹(跨机器UNC,不是 localhost)。我们重命名该文件夹,然后检查新文件夹位置是否存在文件。即使它存在,File.Exists也需要将近5秒钟才能返回true。

可以在https://github.com/davidebbo/NpmFolderRenameIssue找到完整的重播。以下是核心代码:

// This file doesn't exist yet
// Note that the presence of this existence check is what triggers the bug below!!
Console.WriteLine("Exists (should be false): " + File.Exists("test/test2/myfile"));

// Create a directory, with a file in it
Directory.CreateDirectory("test/subdir/test");
File.WriteAllText("test/subdir/test/myfile", "Hello");

// Rename the directory
Directory.Move("test/subdir/test", "test/test2");

var start = DateTime.UtcNow;

// List the files at the new location. Here, our file shows up fine
foreach (var path in Directory.GetFiles("test/test2"))
{
    Console.WriteLine(path);
}

for (; ; )
{
    // Now do a simple existence test. It should also be true, but when
    // running on a (cross machine) UNC share, it takes almost 5 seconds to become true!
    if (File.Exists("test/test2/myfile")) break;

    Console.WriteLine("After {0} milliseconds, test/test2/myfile doesn't show as existing",
        (DateTime.UtcNow - start).TotalMilliseconds);
    Thread.Sleep(100);
}

Console.WriteLine("After {0} milliseconds, test/test2/myfile correctly shows as existing!",
    (DateTime.UtcNow - start).TotalMilliseconds);

因此,初始存在检查似乎会导致存在值被缓存,从而导致这种虚假​​行为。

问题:对此有何解释?什么是避免它的最好方法?

注意:在Windows上使用npm(节点包管理器)时,最初会出现此问题。我这里的代码是repro的C#端口。有关原始Node / npm问题,请参阅https://github.com/isaacs/npm/issues/2230。目标是找到解决它的方法。

3 个答案:

答案 0 :(得分:10)

大卫 重定向器实现了一个否定的“未找到文件”缓存,该缓存可防止客户端使用未找到文件的请求充斥服务器。默认缓存时间为5秒,但您可以修改FileNotFoundCacheLifetime注册表值以控制缓存,或通过将此值设置为0来禁用缓存。

详细信息:http://technet.microsoft.com/en-us/library/ff686200(v=WS.10).aspx

答案 1 :(得分:1)

网络代码中有多种级别的缓存。这可能会减慢文件存在最终显示的时间。

解决方案不是使用文件共享,而是创建一个简单的客户端/服务器体系结构,其中服务器从本地文件系统返回文件存在。这应该真的加快项目检测时间。

我的猜测是,如果你试图打开文件,即使File.Exists说它不存在,但它应该正确打开,以便你可以使用服务器存在信息。如果这不起作用,您只需将下载选项添加到服务器/客户端体系结构。

答案 2 :(得分:1)

一旦我知道“找不到文件”缓存,我就能够通过使用FileInfo对象来解决问题,该对象实现了Refresh()方法。你的代码可以这样做:

FileInfo testFile = new FileInfo("test/test2/myfile");
Console.WriteLine("Exists (should be false): " + testFile .Exists);
Directory.Move("test/subdir/test", "test/test2");
testFile.Refresh();

// the FileInfo object should now be refreshed, and a second call to Exists will return a valid value
if (testFile.Exists)
{
    ...
}