在写入文件后立即读取文件,我得到全零(.net)

发布于 2024-10-12 17:54:47 字数 791 浏览 2 评论 0原文

我有一个程序,需要在文件写入后立即从目录加载文件。我让 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)填充空间和我的空间。程序偶尔会在两者中间跳转。

关于如何编写可靠的代码有什么想法吗?

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

I have a program that needs to load files from a directory as soon as they are written. I got the FileSystemWatcher to notify me of changes to the directory. Rather than check the event for what changed I just list the files and start processing all that I found.

To prevent trying to read a file which is still being written I have code like:

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();
}

The problem is that for some files, about 1 in 200, the program read all zeros. File length is correct but the content appear to be all zero bytes. When I check the file latter I find it does contain actual correct data. I thought the way I was opening the file would prevent premature access to the file.

I'm testing this by copying files to the directory with the DOS command 'copy InFile_0* dropdir' (About 100 files per execution.) Possibly this command does the copy in two steps: 1) allocate space and 2) fill space and my program occasionally jumps in the middle of the two.

Any ideas on how to code this to be reliable?

Update: I don't have control over the writing program - it could be anything. Looks like I have to code defensively.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷离° 2024-10-19 17:54:47

你正在达到竞争条件。除非你彻底修复它,否则情况只会变得更糟(对于网络文件系统等)。

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

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

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

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

You're hitting a race condition. It's only going to get worse from here (with networked file systems etc) unless you fix it definitively.

Try having the program writing the files write each one using a "whatever.tmp" name, then close it, then rename it. When reading, ignore .tmp files.

Or, keep a zero-length file named "sentinel" or some such in the directory. Get the program writing the files to rewrite the sentinel file AFTER each successful write of another file. Then, don't attempt to read files whose modification date/times are >= the modification date/time of the sentinel file.

Or, if you have no control over the writer of the files, check each file's modification date/time against the current system date/time. Let the files age an appropriate amount (a few seconds if they're small, longer if they're larger) before attempting to read them.

Good luck. This is a notorious pain in the neck.

你不是我要的菜∠ 2024-10-19 17:54:47

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

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

我认为你应该更仔细地审视作者的行为。并尝试通过只读、共享所有访问来减少对文件访问的干扰:

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

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

Well, I disagree with previous post by @Ollie Jones.

You already established exclusive access to the file, so no race condition problem.

I think you should examine the writer's behavior more carefully. And try reduce the interference on the file access with read only, share all access:

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

This could fail your read but will reduce write error. To decide when to read safely, you could check on file time or file size or whatever. If many files will be written subsequently you could start read the first file after second file created.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文