← 返回题目列表

Python 文件指针是什么?seek 和 tell 怎么用?

高频 中等 第 11 / 27 题 更新于 2026/07/27
文件指针seektell随机访问

简化版

文件指针表示当前读写位置。tell() 返回当前位置,seek(offset, whence) 移动位置;文本文件中通常只安全使用 seek(0) 或使用 tell() 返回的位置,二进制文件更适合做任意偏移的随机访问。

详细版

每个打开的文件对象都有当前位置:

with open("data.txt", "r", encoding="utf-8") as f:
    print(f.tell())
    print(f.read(5))
    print(f.tell())
    f.seek(0)
    print(f.read(5))

seek() 常见参数:

f.seek(0)        # 回到开头
f.seek(10)       # 移到某个位置
f.seek(0, 2)     # 移到末尾,二进制模式更常用

whence 的含义:

whence含义
0从文件开头计算,默认
1从当前位置计算
2从文件末尾计算

需要注意:文本模式涉及编码和换行转换,偏移不一定等于“字符数量”。如果要按字节精确定位,应该用二进制模式。

完整版教学

一、文件读写为什么需要当前位置

文件可以看成一条很长的数据流,文件对象内部维护一个“当前读写位置”。每次读写都会影响这个位置。

with open("sample.txt", "w+", encoding="utf-8") as f:
    f.write("abcdef")
    print(f.read())   # 读不到内容

为什么读不到?因为写完后位置在文件末尾。要重新从开头读,必须:

with open("sample.txt", "w+", encoding="utf-8") as f:
    f.write("abcdef")
    f.seek(0)
    print(f.read())

这也是 + 模式容易出错的根源之一:你既读又写,就必须知道当前位置在哪里。

二、tell 返回的是什么

tell() 返回文件当前位置。二进制模式下,它通常可以理解为从文件开头开始的字节偏移。

with open("data.bin", "rb") as f:
    f.read(10)
    pos = f.tell()
    print(pos)

文本模式下,tell() 返回的是一个可用于 seek() 的位置标记,不应该简单理解为字符下标。因为文本模式可能发生编码解码和换行转换,一个字符可能占多个字节。

三、seek 的三种定位方式

seek(offset, whence) 用来移动当前位置。

从开头开始:

f.seek(0)
f.seek(100)

从当前位置或末尾计算,在二进制模式里更常见:

with open("data.bin", "rb") as f:
    f.seek(0, 2)       # 到末尾
    size = f.tell()
    f.seek(-100, 2)    # 读取最后 100 个字节
    tail = f.read()

注意:文本模式下不支持所有形式的相对定位。为了避免跨平台、编码和换行带来的问题,面试中可以明确说“任意字节偏移应使用二进制模式”。

四、seek 的常见应用

第一类是重复读取:

with open("config.txt", "r", encoding="utf-8") as f:
    first = f.read()
    f.seek(0)
    second = f.read()

第二类是读取文件尾部,例如简单实现 tail:

with open("app.log", "rb") as f:
    f.seek(0, 2)
    end = f.tell()
    f.seek(max(0, end - 4096))
    data = f.read()

第三类是固定格式文件随机访问,比如某些二进制索引文件、定长记录文件。

五、文本文件随机访问为什么麻烦

假设字符串中有中文:

abc你好

字符数量和字节数量不是一回事。UTF-8 中一个中文通常占 3 个字节。如果你按“第 4 个字符”去套字节偏移,可能刚好跳到一个多字节字符中间,导致解码失败。

因此处理文本内容时,通常优先顺序读取、逐行解析。只有在已经保存了 tell() 的位置标记,或者明确知道底层编码与边界时,才进行定位。

六、常见误区与追问

心法:tell() 记录当前位置,seek() 改变当前位置。对二进制文件可以把它理解成字节偏移;文本文件因为编码和换行转换,随机定位要更谨慎。

  • 误区:tell() 在文本模式下一定等于字符数。 文本模式下返回的是不透明位置标记,不应简单当作字符下标;多字节编码和换行转换会让字符数与字节偏移不同。
  • 追问:seek(offset, whence)whence 有哪些值? 0 表示从文件开头,1 表示从当前位置,2 表示从文件末尾;文本模式下非零相对偏移支持受限,二进制模式更适合随机访问。
  • 误区:读完文件后再次读取会自动从头开始。 文件对象有当前位置,读到末尾后继续读会得到空内容;要重新读需要 seek(0)
  • 追问:为什么大文件尾部读取常用二进制模式? 从文件末尾按字节倒退更可控,避免文本解码边界和换行转换干扰;找到边界后再解码文本更稳。
  • 误区:seek 会改变文件内容。 seek 只移动当前位置,不写入数据;真正改变内容的是后续 write、截断等操作。
  • 追问:读写混合模式为什么容易出错?r+w+ 等模式中,读写共享同一个位置,读后写、写后读通常要配合 seekflush,否则位置和缓冲状态容易混乱。

七、加强记忆

文件指针就是“下一次读写从哪里开始”。read()write() 会移动它,tell() 告诉你当前位置,seek() 让你跳到指定位置。文本模式关注字符语义,随机偏移容易被编码和换行影响;二进制模式关注字节,更适合精确定位。