ZetCode

Python seek 函数

最后修改时间:2025 年 3 月 26 日

这篇全面的指南探讨了 Python 的 seek 函数,这是一种在 Python 中进行文件定位的强大方法。我们将介绍基本用法、定位模式、实际示例和最佳实践。通过详细的示例,您将掌握 Python 中的随机文件访问。

基本定义

seek 函数改变文件流中的当前文件位置。它接受两个参数:offset(位置)和 whence(参考点)。该函数返回文件中新的绝对位置。

文件位置以从文件开头开始的字节数来衡量。whence 参数确定参考点:0(开始)、1(当前位置)或 2(结束)。在文本文件中,只允许相对于起点的查找。

基本的 seek 用法

seek 最简单的用法是从文件开头移动到特定位置。此示例演示了从不同位置读取。

basic_seek.py
# Basic seek example
with open('example.txt', 'r') as file:
    file.seek(10)  # Move to 10th byte
    print("From position 10:", file.read(5))
    file.seek(0)   # Return to start
    print("From start:", file.read(5))

这段代码首先移动到位置 10,读取 5 个字符,然后返回到开头再次读取。seek 操作是立即的,不涉及读取任何数据。它只会改变下一次读取或写入将发生的位置。

请记住,在文本模式下,查找任意位置可能会由于换行符转换而产生意外的结果。二进制模式提供对文件定位的更精确控制。

从当前位置搜索

使用 whence=1 允许相对于当前位置查找。这对于跳过或倒回少量内容而无需计算绝对位置非常有用。

seek_current.py
# Seeking from current position
with open('data.bin', 'rb') as file:
    print("First 5 bytes:", file.read(5))
    file.seek(3, 1)  # Skip 3 bytes from current
    print("Next 5 bytes:", file.read(5))
    file.seek(-5, 1)  # Rewind 5 bytes
    print("Same 5 bytes:", file.read(5))

此二进制模式示例读取 5 个字节,跳过 3 个字节,再读取 5 个字节,然后倒回 5 个字节再次读取相同的数据。第二个参数 (1) 使偏移量相对于当前位置。负偏移量向后移动。

请注意,在大多数情况下,从当前位置查找需要二进制模式。由于平台之间的换行符转换,文本模式可能不支持相对查找。

从文件末尾搜索

使用 whence=2 允许相对于文件末尾查找。这通常用于读取文件的最后一部分或追加数据。

seek_end.py
# Seeking from end of file
with open('large.log', 'rb') as file:
    file.seek(-100, 2)  # Last 100 bytes
    last_part = file.read()
    print("Last 100 bytes:", last_part)
    
    # Append without overwriting
    file.seek(0, 2)
    file.write(b'\nNew log entry')

此示例首先读取日志文件的最后 100 个字节,然后移动到末尾以追加新数据。seek(0, 2) 模式是定位到末尾进行追加的常用方法。文件必须以允许写入的模式打开才能进行追加操作。

从末尾查找时,通常使用负偏移量来定位到末尾之前。零偏移量正好位于末尾,这对于将数据追加到文件很有用。

文本模式查找的限制

由于换行符转换,文本模式查找有局限性。此示例演示了在使用文本文件时遇到的挑战和解决方案。

text_seek.py
# Text mode seeking challenges
with open('textfile.txt', 'r+') as file:
    # Safe seek - only to positions from tell()
    pos = file.tell()
    content = file.read(10)
    file.seek(pos)  # Return to recorded position
    
    # Binary mode alternative for precise seeking
    with open('textfile.txt', 'rb') as bin_file:
        bin_file.seek(20)
        print("Binary mode precise seek:", bin_file.read(5))

这段代码展示了两种方法:使用 tell 记录位置以便在文本模式下安全查找,以及使用二进制模式进行精确定位。文本模式将特定于平台的行尾符转换为 \n,使得字节计数对于查找不可靠。

为了实现可靠的文本文件查找,可以使用从 tell 获取的位置,或者以二进制模式打开文件并手动处理编码。后一种方法提供完全控制,但需要更多的工作。

结合 seek 和 readline

此示例演示了如何将 seekreadline 结合使用,以实现对文件中特定行的有效随机访问。

seek_readline.py
# Random line access with seek
def get_line(filepath, line_num):
    with open(filepath, 'rb') as file:
        # Find line start positions
        positions = [0]
        while file.readline():
            positions.append(file.tell())
        
        if line_num >= len(positions):
            return None
            
        file.seek(positions[line_num])
        return file.readline().decode('utf-8')

# Get 5th line (0-based index)
print("5th line:", get_line('data.txt', 4))

此函数首先扫描文件以记录所有行的起始位置,然后使用 seek 直接跳转到所需的行。二进制模式确保精确定位,而 decode 处理文本转换。对于重复随机访问同一文件,这种方法是有效的。

对于非常大的文件,存储所有行位置可能会占用太多内存。在这种情况下,请考虑替代方法,如二分查找或维护外部行索引。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程