4

我有一个程序需要在写入文件后立即从目录中加载文件。我让 FileSystemWatcher 通知我目录的更改。我没有检查事件的变化,而是列出文件并开始处理我找到的所有内容。

为了防止尝试读取仍在写入的文件,我有如下代码:

try {
    fs = fi.Open(FileMode.Open, FileAccess.ReadWrite,
                    FileShare.None);
    message = new byte[fs.Length];
    int br = fs.Read(message, 0, (int)fi.Length);
}
catch (Exception e) {
    // I'll get it next time around
    return;
}
finally {
    if (fs != null)
        fs.Close();
}

问题是对于某些文件,大约 200 个文件中的 1 个,程序读取全零。文件长度正确,但内容似乎全为零字节。当我稍后检查文件时,我发现它确实包含实际正确的数据。我认为我打开文件的方式可以防止过早访问该文件。

我正在通过使用 DOS 命令“copy InFile_0* dropdir”将文件复制到目录来测试这一点(每次执行大约 100 个文件。)这个命令可能分两个步骤进行复制:1)分配空间和 2)填充空间和我的程序偶尔会在两者中间跳转。

关于如何将其编码为可靠的任何想法?

更新: 我无法控制写作程序——它可以是任何东西。看来我必须进行防御性编码。

4

2 回答 2

2

你遇到了比赛条件。除非你彻底修复它,否则它只会从这里变得更糟(使用网络文件系统等)。

尝试让编写文件的程序使用“whatever.tmp”名称写入每个文件,然后关闭它,然后重命名它。阅读时,忽略 .tmp 文件。

或者,在目录中保留一个名为“sentinel”或类似名称的零长度文件。让程序写入文件以在每次成功写入另一个文件后重写哨兵文件。然后,不要尝试读取修改日期/时间 >= 标记文件的修改日期/时间的文件。

或者,如果您无法控制文件的编写者,请根据当前系统日期/时间检查每个文件的修改日期/时间。在尝试读取文件之前,让文件老化适当的时间(如果它们很小,则几秒钟,如果它们较大,则更长)。

祝你好运。这是众所周知的颈部疼痛。

于 2011-01-20T00:23:07.090 回答
1

好吧,我不同意@Ollie Jones 之前的帖子。

您已经建立了对该文件的独占访问权限,因此没有竞争条件问题。

我认为你应该更仔细地检查作者的行为。并尝试以只读方式减少对文件访问的干扰,共享所有访问权限:

fi.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

这可能会使您的读取失败,但会减少写入错误。要决定何时安全阅读,您可以检查文件时间或文件大小等。如果随后将写入许多文件,您可以在创建第二个文件后开始读取第一个文件。

于 2011-01-20T16:42:20.133 回答