macOS下文件处理程序运行状态对文件缓冲区自动刷新的影响问题
macOS 未刷缓冲文件打开行为差异原因解析
核心结论
测试程序的libc用户态文件缓冲区刷新逻辑本身完全不受外部文件处理程序运行状态的影响,差异来自open命令的执行逻辑和文件读取的时机差:
- 文件处理程序未启动时,新进程启动的延迟刚好让测试程序赶在文件读取前完成了
fclose自动刷缓冲的操作 - 文件处理程序已启动时,程序收到打开请求后立刻读取文件,此时缓冲还未刷入磁盘,因此读取到残缺内容
详细逻辑
- 恒定前提:C标准库的
FILE*缓冲区是进程用户态的私有内存,未调用fflush()/fclose()前,写入的内容仅存在于测试程序内存中,操作系统内核、其他进程都看不到这些内容,对应磁盘上的文件始终是不完整的,这个状态和其他程序是否运行无关。 - 处理程序未运行时的正常打开逻辑:
- 调用
system("open test.rtf")后,open命令会先启动对应的文件处理程序进程,进程启动、资源加载需要至少几十到几百毫秒 open命令完成进程创建操作后就会退出,system调用返回,测试程序接下来执行fclose(fout),自动触发缓冲区刷写,把完整内容写入磁盘- 此时文件处理程序刚完成启动,第一次读取文件时拿到的已经是刷入后的完整内容,因此表现正常。
- 调用
- 处理程序已运行时的报错逻辑:
- 调用
system("open test.rtf")后,open命令不需要创建新进程,直接向已运行的处理程序进程发送IPC打开通知,处理程序收到通知后会立即读取目标文件 - 此时测试程序还在等待
open命令返回,还没执行到fclose(fout)的逻辑,磁盘上的文件仍然是残缺状态,因此处理程序会报文件截断/损坏错误。
- 调用
- sleep无效的原因:sleep逻辑放在
system调用之前执行,sleep过程中始终没有触发缓冲区刷写,磁盘上的文件一直是残缺状态,等待再久也不会改变这个状态。
代码示例
未显式刷新版本(仅当文件处理程序未运行时可用)
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <unistd.h> int main(void) { FILE *fin = fopen("src.rtf", "rb"); FILE *fout = fopen("test.rtf", "wb"); int c; assert(fin && fout); while ((c=fgetc(fin)) != EOF) fputc(c, fout); sleep(3); system("open test.rtf"); fclose(fin); fclose(fout); return 0; }
显式刷新版本(所有场景下均可用)
#include <stdio.h> #include <stdlib.h> #include <assert.h> int main(void) { FILE *fin = fopen("src.rtf", "rb"); FILE *fout = fopen("test.rtf", "wb"); int c; assert(fin && fout); while ((c=fgetc(fin)) != EOF) fputc(c, fout); fflush(fout); system("open test.rtf"); fclose(fin); fclose(fout); return 0; }
内容的提问来源于stack exchange,提问作者torstenvl
相关产品推荐
相关产品推荐

