使用fseeko64在EOF后寻址写入未创建稀疏文件空洞的问题
问题根因
你使用的文件打开标识包含a(append追加模式),这是导致写入被强制顺序追加、无法生成文件空洞的直接原因。
根据C标准库的强制行为定义:只要以带a的模式打开文件,无论之前通过fseeko64把文件指针设置到哪个位置,所有fwrite写操作都会被强制定位到文件的实际末尾执行。
为什么调试排查时找不到问题
你在断点中看到偏移量计算正确、fseeko64返回值为0,是因为fseeko64确实修改了FILE结构体内部记录的逻辑偏移值。但进入实际写入环节时,stdio库会偷偷把这个偏移值重置为当前文件的真实长度,再执行写入操作。
对应你的最小复现代码流程:
- 第一次打开文件写入
data块,文件长度从0增长为40字节(10个uint32的总大小) - 第二次打开文件依然用了
"ar+b"模式,你手动把偏移设置为900,但执行fwrite时,偏移被自动重置到40字节的位置,直接把data2块追加在第一块后面 - 最后你从900偏移位置读取时,读到的是从未被写入的未分配磁盘块(也就是本该生成空洞的区域),自然和预期存在900位置的
data2内容不匹配
这也完全解释了你用十六进制转储看到的现象:两个数据块完全顺序拼接,中间根本没有留出空隙。
修正方案
所有写操作场景下,直接去掉打开模式里的a标识即可。如果需要兼容“文件不存在时自动创建、存在时不截断原有内容”的需求,按如下逻辑处理:
// 先尝试以可读写、不截断原有内容的模式打开 FILE* file = fopen64(fn.c_str(), "r+b"); if (file == nullptr) { // 文件不存在时,以可读写、创建新文件的模式打开 file = fopen64(fn.c_str(), "w+b"); }
补充说明:append模式的设计目标是支持多进程并发写同一个日志文件时,避免写入覆盖、内容错位,它天生不支持随机按偏移写入的场景,完全不适合存储稀疏结构数据。
内容的提问来源于stack exchange,提问作者T.Aoukar
相关产品推荐
相关产品推荐

