删除()打开文件是否“安全”?

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

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

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

(当然,添加了error handling)

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

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

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

你有什么看法/经验? 我要担心吗? 我应该避免这种解决方案?

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

编辑:好的,还有一个问题:在这种特殊情况下,我提出的解决方案是否可能比仅仅打开输出文件只写(例如上面但没有remove()调用)更加邪恶。

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

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

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

如果文件很大,并且空间非常宝贵,并且开发人员的时间很便宜,那么您可以打开一个用于读/写的文件,并确保您的写指针不会超出读指针。

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

我总是让它在Linux / Unix上运行。 从不在Windows,OS / 2或(颤抖)DOS上。 您关注的任何其他平台?

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