我考虑添加将输入和输出文件的文件名同样用于我的程序的可能性,以便它将替换输入文件。
由于处理过的文件可能非常大,我认为最佳解决方案是先打开文件,然后将其删除并创建一个新文件,即:
/* input == output in this case */
FILE *inf = fopen(input, "r");
remove(output);
FILE *outf = fopen(output, "w");
(当然,添加了错误处理)
我知道并非所有系统都允许我删除打开的文件,只要remove()
在这种情况下失败就可以接受。
我很担心,如果没有任何系统允许我删除该打开文件,然后无法读取其内容。
C99标准将该情况下的行为指定为“实现定义”; SUS甚至没有提到这个案例。
您的意见/经验是什么?我要担心吗?我应该避免这样的解决方案吗?
编辑:请注意这不应该是一些主线功能,而是“最后的手段”,如果用户指定相同的文件名作为输入和输出文件。
编辑:好的,还有一个问题:在这种特殊情况下,我提出的解决方案是否有可能比只打开输出文件只做更多的邪恶(例如上面但没有{{1调用)。
答案 0 :(得分:4)
我知道的所有可以删除打开文件的系统都会为文件节点实现某种形式的引用计数。因此,删除文件会删除目录条目,但文件节点本身仍然有一个来自打开文件句柄的引用。在这样的实现中,删除文件显然不会影响继续阅读它的能力,我发现很难想象有任何其他合理的方法来实现这种行为。
答案 1 :(得分:4)
不,它不是安全。它可能适用于您的文件系统,但在其他文件系统上失败。或者它可能会间歇性地失败。这实际上取决于您的操作系统和文件系统。要深入了解Solaris,请参阅此article on file rotation。
看看GNU sed's '--in-place' option。此选项的工作原理是将输出写入临时文件,然后复制原始文件。这是唯一安全,兼容的方法。
您还应该考虑到您的程序可能会在任何时候失败,因为停电或进程被杀死。如果发生这种情况,则原始文件将丢失。此外,对于具有引用计数的文件系统,不要在临时文件解决方案中保存任何空间,因为在输入文件关闭之前,两个文件都必须存在于磁盘上。
如果文件很大,并且空间非常宝贵,并且开发人员的时间很便宜,那么您可以打开一个用于读/写的文件,并确保您的写指针不会超出读指针。
答案 2 :(得分:1)
我总是让它在Linux / Unix上运行。从不在Windows,OS / 2或(颤抖)DOS上。您关注的任何其他平台?
此行为实际上在使用临时磁盘空间时很有用 - 打开文件进行读/写,并立即将其删除。它会在程序退出时自动清理(出于任何原因,包括断电),并使其他人更难(但并非不可能)监视它(如果您对该进程具有读取权限,则proc可以提供线索)