C语言 1000问 · 文件I/O Q4:fseek / ftell / rewind 怎么用?文本模式和二进制模式下的定位有什么不同?

来源:Flomo 原始笔记|查看原笔记|迁移日期:2026-10-31

C语言 1000问 · 文件I/O Q4:fseek / ftell / rewind 怎么用?文本模式和二进制模式下的定位有什么不同?

▎ 五大学习法:西蒙学习法——把「文件定位」钻透

三个基本定位函数

  • ftell(fp):返回当前位置相对文件开头的偏移。常用于「记住当前位置,之后跳回来」。
  • fseek(fp, offset, whence):移动位置指针。
    • whence 三个取值:SEEK_SET(文件开头,offset 非负)、SEEK_CUR(当前位置,可正可负)、SEEK_END(文件末尾,通常为负或 0)。
    • 返回 0 成功、非 0 失败。
  • rewind(fp):回到文件开头,等价 fseek(fp, 0, SEEK_SET),但它还会清除错误标志(feof / ferror)。

典型用法

  • 求文件大小:fseek(fp, 0, SEEK_END); n = ftell(fp); rewind(fp);
  • 定位到第 k 条记录:fseek(fp, k * sizeof(Record), SEEK_SET);
  • 回退到上一个位置:pos = ftell(fp); …; fseek(fp, pos, SEEK_SET);

文本模式和二进制模式下的差别

  • 二进制模式:位置就是「真实的字节偏移」,定位精确、可任意跳转——推荐用二进制定位。
  • 文本模式:因为换行翻译,ftell 返回的值不一定等于真实字节偏移(尤其 Windows 上 ‘\r\n’ 与 ‘\n’ 互转)。标准只保证 ftell 的值能原样传给 fseek(同一文件、同一模式下)用。
  • 文本模式下理论上只能 fseek 到「ftell 返回过的位置」或文件开头 / 末尾,不支持任意中间偏移。
  • Unix 上文本模式不做翻译,两者基本一致;为可移植,做字节级定位就一律用二进制模式。

几个坑

  • fseek 超出文件末尾不报错(可跳到末尾之后再写,中间成空洞、读为 0)。
  • fseek 只适用于可定位流:管道、终端、socket 不能 fseek。
  • 用 fseek 后缓冲状态会重置;“r+” 读写切换时中间必须有 fflush 或 fseek,否则未定义。
  • rewind 会清除错误标志,想「复位又清错误」时方便,但想保留错误状态就别用。
  • ftell 返回 long,超大文件(> 2GB)要用 fseeko / ftello(POSIX)或 _fseeki64。

一句话:ftell 记位置、fseek 跳位置、rewind 回开头(还清错误标志);二进制模式下位置就是真实字节偏移、可任意跳,文本模式因换行翻译只保证「fseek 到 ftell 给过的位置」——要精确字节定位就用二进制模式。

📎 问题库(专栏⑭导航)→ https://v.flomoapp.com/mine/?memo_id=MjQ1NzM0NTk5

📎 文件I/O Q3(feof 的坑)→ https://v.flomoapp.com/mine/?memo_id=MjU2NDUwNDg4

C语言