如何通过编程强制Windows在文件正在写入时更新文件报告的磁盘大小?

6
我有一个程序,它打开一个ASCII日志文件,并在事件发生时向其末尾写入文本行。事件的时间是不可预测的;它们可能每秒发生多次,也可能每隔几个小时才发生一次。
这一切都很好;问题出现在当我想在程序运行时查看日志文件的当前大小时。在Windows下,如果我在DOS shell中输入dir,直到我的程序关闭日志文件之前,日志文件的大小显示为0字节。(有趣的是,如果我执行dir my_file_name.log,则文件的大小会更新,但只有一个普通的dir不会更新文件大小)
这比我想要的要少用一些;然而根据SuperUser.com上这个问题/答案(链接),这种行为是Windows操作系统的“特性”。该答案甚至提供了一个hack解决方法来强制更新文件大小(通过在DOS框中输入type my_file_name.log > nul)。

我的问题是,是否有一种编程方式可以在程序内部强制执行相同的更新?我希望能够偶尔强制显示正确的大小,而不必告诉用户手动执行解决步骤。

我尝试通过在程序内模拟type的行为,对我的日志文件路径进行单独调用fopen()fclose(),但似乎没有任何效果。

我还尝试通过在我的日志文件句柄上调用fclose(),然后立即通过fopen()再次以追加模式打开文件来强制执行此操作,但由于某种原因fopen()调用失败。(我真的不想这样做,因为重新打开文件可能会失败,使我的程序处于不良状态)

请参见下面的玩具示例程序:

#include <stdio.h>

int main(int args, char ** argv)
{
   FILE * fpOut = fopen("my_log_file.txt", "w");
   if (fpOut)
   {
      for (int i=0; i<1000; i++)
      {
         fprintf(fpOut, "Event %i occurred\n", i);
         fflush(fpOut);

         Sleep(1000);

         // is there something I could call here to make the file's new size visible to the world?
      }
      fclose(fpOut);
   }
   return 0;
}

我必须承认,我很想知道一个实际的答案。我已经开始尽可能地调整读取器,以正确的方式请求它,这样它就不会得到缓存值。(提示:cygwin的ls不会被愚弄。) - Joshua
如果您已经打开了文件,难道不能直接使用 ftell 吗? - Jonathan Potter
@JonathanPotter - ftell 有什么意义? - RbMm
我认为在这里最好的做法是调用GetFileAttributesW函数。 - RbMm
1个回答

0

你可以像 linked port 建议的那样执行以下操作:打开并关闭它

可以使用任何打开文件(创建单独的 SFT 条目)并再次关闭它的工具。它可以是一些简单的东西,比如在另一个控制台/会话中运行的 type 命令:type file > nul

尝试类似这样的操作:

if ((i % 10) == 0) {
    FILE* tmp = fopen("my_log_file.txt", "r");
    if (tmp) fclose(tmp);
}

注意:它会打开新的描述并关闭它,原始写入不受影响。


调用“ZwQueryAttributesFile”足够了。 - RbMm
正如我在问题中提到的那样,我尝试了fopen()/fclose()技巧,但似乎并没有起作用... fopen()只是返回NULL,文件大小也没有改变。 - Jeremy Friesner
@JeremyFriesner 我在 Windows 10 上测试了它,使用 msvc - 像魔法一样工作,如果你从 fopen 中得到 null,则检查 errno 查找实际问题。 - Iłya Bursov
@IłyaBursov 我检查了 errno,它被设置为 13/权限被拒绝。 - Jeremy Friesner
1
“你可以按照Linked Port的建议去做:打开并关闭它。” - 这不是Super User问答所建议的。它明确解释说,只有当所有文件句柄都关闭后,目录条目才会得到更新。随意创建一个新的文件句柄并关闭它并不能满足这个条件。 - IInspectable
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接