C语言文本文件中fseek()可靠性及搭配ftell()用法的相关疑问
关于C语言文本模式下fseek()的常见问题解答
为什么fseek()在文本文件中无法保证任意偏移都正常运行
C标准中,文件打开分为文本模式和二进制模式两种,二者的核心差异就是文本模式会自动处理系统相关的特殊字符转换:
- 比如Windows平台下文本文件的换行实际存储为
\r\n两个字节,文本模式读取时会自动合并为单个\n返回,写入时又会把\n拆成\r\n写入 - 部分旧系统还会存在文本文件结束符、行尾填充字符等其他特殊转换规则
这种转换会导致你读写时感知到的逻辑位置,和文件实际物理存储的字节位置不匹配,而C标准没有要求标准库支持文本模式下的任意数值偏移寻址,只有两种fseek操作是被标准明确保证安全的:
- 偏移量为0,相对于文件开头寻址(
SEEK_SET),即直接回到文件头 - 偏移量为之前
ftell()返回的有效值,相对于文件开头寻址
其他所有用法(比如自己随便填偏移量、相对于当前位置SEEK_CUR/文件末尾SEEK_END做非0偏移)都属于未定义行为,这就是大家常说fseek不能随便用在文本文件上的原因。
先调用ftell()存位置再用fseek()跳回的用法是否正确
这个说法是正确的,完全符合C标准要求。ftell()在文本模式下返回的不是普通的物理字节偏移,而是标准库内部维护的、可以唯一标识文件位置的特殊标记值,这个值的唯一用途就是传给fseek()搭配SEEK_SET使用,保证可以准确跳转到之前记录的位置。
注意你提到的代码存在笔误,标准正确写法如下:
// 记录当前文件位置 long pos = ftell(file); // 中间执行其他文件读写操作 // 跳转回之前记录的位置 fseek(file, pos, SEEK_SET);
这种用法无论在文本模式还是二进制模式下都是完全安全的。
读写回写场景的额外注意事项
如果你需要在同一个文件流上交替执行读和写操作,每次切换操作类型之前,必须调用fflush()、fseek()、fsetpos()或者rewind()做同步,否则行为是未定义的,读写原文件的场景很容易踩到这个坑。
内容的提问来源于stack exchange,提问作者Ignacio Romero
相关产品推荐
相关产品推荐

