4

我考虑在我的程序中添加对输入和输出文件使用相同文件名的可能性,以便它将替换输入文件。

由于处理后的文件可能很大,我认为最好的解决方案是首先打开文件,然后将其删除并创建一个新文件,即这样:

/* input == output in this case */
FILE *inf = fopen(input, "r");
remove(output);
FILE *outf = fopen(output, "w");

(当然,添加了错误处理)

我知道并非所有系统都允许我删除打开的文件,只要remove()在这种情况下会失败,这是可以接受的。

我担心如果没有任何系统允许我删除该打开的文件然后无法读取其内容。

C99 标准将这种情况下的行为指定为“实现定义的”;SUS 甚至没有提到这个案子。

你的意见/经验是什么?我需要担心吗?我应该避免这样的解决方案吗?

编辑:请注意,这不应该是一些主线功能,而是在用户指定相同文件名作为输入和输出文件的情况下的“最后手段”。

编辑:好的,还有一个问题:在这种特殊情况下,我提出的解决方案是否有可能比仅以只写方式打开输出文件(即像上面一样但没有remove()调用)做更多的坏事。

4

3 回答 3

4

我所知道的所有允许您删除打开文件的系统都为文件节点实现了某种形式的引用计数。因此,删除文件会删除目录条目,但文件节点本身仍然有一个来自打开文件句柄的引用。在这样的实现中,删除文件显然不会影响继续阅读它的能力,而且我发现很难想象有任何其他合理的方式来实现这种行为。

于 2009-09-02T22:51:58.610 回答
4

不,这不安全。它可能在您的文件系统上工作,但在其他文件系统上失败。或者它可能会间歇性地失败。这实际上取决于您的操作系统和文件系统。要深入了解 Solaris,请参阅这篇关于文件轮换的文章。

看看GNU sed 的 '--in-place' 选项。此选项通过将输出写入临时文件,然后复制原始文件来工作。这是唯一安全、兼容的方法。

您还应该考虑到,由于断电或进程被终止,您的程序可能随时失败。如果发生这种情况,那么您的原始文件将丢失。此外,对于确实具有引用计数的文件系统,您不会在临时文件解决方案上节省任何空间,因为两个文件都必须存在于磁盘上,直到输入文件关闭。

如果文件很大,空间很宝贵,而且开发人员的时间很便宜,你可以打开一个文件进行读/写,并确保你的写指针不会超过你的读指针。

于 2009-09-02T23:12:53.840 回答
1

我总是让它在 Linux/Unix 上工作。永远不要在 Windows、OS/2 或(颤抖的)DOS 上。您还关心其他任何平台吗?

这种行为实际上在使用临时磁盘空间时很有用——打开文件进行读/写,然后立即删除它。它会在程序退出时自动清理(出于任何原因,包括断电),并使其他人更难(但并非不可能)监视它(/proc 可以提供线索,如果您对该进程具有读取权限) .

于 2009-09-02T22:57:26.647 回答