Linux下C应用读取被改写文件时能否确保获取旧内容?
问题解答
首先明确结论:不能保证仅获取旧内容,结果完全取决于另一个应用改写文件的方式,分两种核心场景:
1. 另一个应用直接覆盖原文件内容(同inode修改)
当你用fopen打开文件后,拿到的是对应文件inode的引用。如果另一个应用通过以下方式修改文件:
- 用
fopen("file", "w")截断原文件后写入新内容 - 用
write系统调用在文件原有偏移位置覆盖写入 - 用
truncate修改文件大小后写入
这种情况下,文件的inode并未改变,只是对应的数据块被修改。你的应用后续调用fgets时,会从当前文件偏移位置读取最新的文件内容(注意:标准C库的FILE*有缓冲区,已经读到缓冲区的内容是旧的,但缓冲区耗尽后会从文件重新读取新内容)。
2. 另一个应用通过替换文件修改(新inode替换)
如果另一个应用采用“写临时文件+rename替换”的方式(这是很多工具的安全改写方式):
- 先将新内容写入临时文件(比如
file.tmp) - 调用
rename("file.tmp", "file")替换原文件
此时原文件的inode依然被你的应用持有(未调用fclose),而原文件名已经指向新的inode。你的应用后续读取的始终是旧inode对应的内容,直到调用fclose后重新打开文件,才会看到新的内容。
关于你的小文件测试结果
你测试得到“仅读到旧内容”的结果,大概率是因为测试时用了文件替换的改写方式,而非直接覆盖。如果换成直接覆盖的方式测试,就能观察到读取到新内容的情况。
如何确保只读旧内容
如果需要严格保证读取过程中不受其他应用修改的影响,有两种可靠方式:
- 读取前将文件完整复制到临时文件,然后读取临时文件
- 对原文件加独占读锁(比如用
flock系统调用),阻止其他应用修改,读取完成后释放锁
内容的提问来源于stack exchange,提问作者Jay Smith
相关产品推荐
相关产品推荐

