在Windows中通过重命名覆盖文件随机失败

我有一个文本文件,我想通过将其重写到临时文件,然后覆盖原来编辑。 这段代码并没有做到这一点,因为它简化了,但它确实包含了我的问题。 在Windows上,如果重命名函数失败,那么EXAMPLE.TXT文件将在似乎随机数的运行后消失。 我不知道为什么,但到目前为止,它在Linux上运行良好。 为什么会发生这种情况?我怎样才能解决这个问题呢?比如在程序中覆盖原始文件而不重命名?

此外还有哪些更好的方法? 这个方法在Windows上有其他的缺陷,比如程序在调用remove的时候被closures了,但是在重命名之前,这在Linux上不会有问题(在删除remove之后)?

#include <stdio.h> #include <assert.h> int main(int argc, char *argv[]) { unsigned int i=0; FILE *fileStream, *tempStream; char fileName[] = "EXAMPLE.TXT"; char *tempName = tmpnam(NULL); while(1) { printf("%u\n",i++); assert(fileStream = fopen(fileName, "r+")); assert(tempStream = fopen(tempName, "w")); fprintf(tempStream,"LINE\n"); fflush(tempStream); /* fclose alone is enough on linux, but windows will sometimes not fully flush when closing! */ assert(fclose(tempStream) == 0); assert(fclose(fileStream) == 0); assert(remove(fileName) == 0); /* windows fails if the file already exists, linux overwrites */ assert(rename(tempName,fileName) == 0); } } 

有时防病毒软件会在不方便的时候通过扫描文件来引起这样的问题。

如果remove失败,请尝试短时间睡眠,然后重试。

这样做的确有可能造成麻烦。 在Windows上,您的代码有四种可能的结果:

  • 删除好,重命名作品,没问题
  • 删除罚款,但另一个进程已打开的文件与删除共享。 通常用于恶意软件扫描程序和文件内容索引器。 这确保文件的最后一个句柄关闭时,文件实际上被删除。 问题是,重命名失败,因为该文件仍然存在
  • 不会因为文件被锁定而被删除,你的断言会被触发
  • 什么都不会发生,因为在构建发行版本时,assert()是无操作的。

顺便说一下,最后一个子弹的可能性很大,这当然可以解释可重复的失败。 你需要更多的防御策略来处理第二个子弹:

  • 删除filename.bak,如果失败则报告错误
  • 将fileName重命名为filename.bak,如果失败则报告错误
  • 将tempName重命名为文件名,报告错误,如果失败,则重命名filename.back
  • 删除filename.bak,不要报错

这是一个常见的情况,winapi有一个函数ReplaceFile() 。 一定要使用备份文件选项来最大限度地降压。 –