Python os.lseek 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨了 Python 的 os.lseek
函数,该函数用于更改文件位置以便读取/写入。我们将介绍定位模式、偏移量处理以及实际的文件操作示例。
基本定义
os.lseek
函数更改文件描述符的文件位置。它是一个底层操作,类似于 C 库的 lseek。
关键参数:fd(文件描述符),pos(偏移量),whence(参考点:SEEK_SET,SEEK_CUR,SEEK_END)。返回新的绝对位置。
从文件开头定位
SEEK_SET 模式从文件开头定位。此示例演示了通过定位到绝对位置来读取文件的特定部分。
import os # Create a test file with open("data.bin", "wb") as f: f.write(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ") # Open and seek fd = os.open("data.bin", os.O_RDONLY) os.lseek(fd, 10, os.SEEK_SET) # Seek to 11th byte (0-based) data = os.read(fd, 5) print(f"Read from position 10: {data.decode()}") # KLMNO os.close(fd)
这会创建一个包含字母表的二进制文件,然后定位到位置 10。读取操作从“K”开始,并向前读取 5 个字节。
请记住,文件位置在 Python 中是从 0 开始的。SEEK_SET,pos=0 是文件开头。
从当前位置搜索
SEEK_CUR 模式相对于当前位置进行定位。这允许向前/向后移动,而无需知道绝对位置。
import os fd = os.open("data.bin", os.O_RDONLY) # Initial read data = os.read(fd, 5) print(f"First 5 bytes: {data.decode()}") # ABCDE # Seek forward 5 bytes os.lseek(fd, 5, os.SEEK_CUR) data = os.read(fd, 5) print(f"Next 5 bytes: {data.decode()}") # KLMNO # Seek backward 10 bytes os.lseek(fd, -10, os.SEEK_CUR) data = os.read(fd, 5) print(f"Rewound 10 bytes: {data.decode()}") # FGHIJ os.close(fd)
这显示了从当前位置向前和向后定位。第二个 seek 从当前位置向后移动 10 个字节。
负偏移量向后移动,正偏移量向前移动。该位置不能在文件开头之前。
从文件末尾定位
SEEK_END 模式相对于文件末尾进行定位。这对于追加或读取文件末尾而无需知道其确切大小非常有用。
import os fd = os.open("data.bin", os.O_RDONLY) # Get file size by seeking to end file_size = os.lseek(fd, 0, os.SEEK_END) print(f"File size: {file_size} bytes") # 26 # Read last 5 bytes os.lseek(fd, -5, os.SEEK_END) data = os.read(fd, 5) print(f"Last 5 bytes: {data.decode()}") # VWXYZ # Seek beyond end (creates 'hole' in sparse files) new_pos = os.lseek(fd, 100, os.SEEK_END) print(f"New position: {new_pos}") # 126 os.close(fd)
这演示了通过定位到末尾来获取文件大小、读取最后几个字节以及定位到超出末尾(这可能会创建稀疏文件)。
定位到超出末尾不会立即分配空间。该文件看起来更大,但在数据写入特定位置之前不会使用磁盘空间。
修改文件内容
将 lseek 与写入操作相结合可以实现精确的文件修改。此示例显示了就地更新,而无需重写整个文件。
import os # Create initial file with open("records.dat", "wb") as f: f.write(b"RECORD1DATAXXXXX") # Open for read-write fd = os.open("records.dat", os.O_RDWR) # Update specific record os.lseek(fd, 7, os.SEEK_SET) # Position after "RECORD1" os.write(fd, b"UPDATED") # Verify change os.lseek(fd, 0, os.SEEK_SET) data = os.read(fd, 20) print(f"Modified content: {data.decode()}") # RECORD1UPDATEDXX os.close(fd)
这会创建一个带有占位符数据的文件,然后定位到位置 7 以覆盖部分内容。文件的其余部分保持不变。
对于固定长度的记录文件,lseek 提供了高效的随机访问,而无需加载整个文件。
处理大文件
os.lseek 支持大文件(>2GB),通过返回和接受 64 位偏移量。此示例演示了处理大文件位置。
import os # Create a large sparse file (doesn't use actual disk space) fd = os.open("large.bin", os.O_WRONLY | os.O_CREAT, 0o644) os.lseek(fd, 2**32, os.SEEK_SET) # 4GB position os.write(fd, b"END") os.close(fd) # Verify the large file fd = os.open("large.bin", os.O_RDONLY) size = os.lseek(fd, 0, os.SEEK_END) print(f"File size: {size} bytes") # 4294967299 (4GB + 3 bytes) # Read the written data os.lseek(fd, 2**32, os.SEEK_SET) data = os.read(fd, 3) print(f"Data at 4GB offset: {data.decode()}") # END os.close(fd)
这会创建一个在 4GB 偏移量处具有数据的稀疏文件。在将数据写入特定位置之前,实际磁盘使用量非常小。
在大多数现代系统中,Python 的 os.lseek 支持最大 2^63-1 字节(8艾字节)的文件大小。
查找当前位置
使用偏移量 0 和 SEEK_CUR 调用 lseek 会返回当前位置,而不会更改它。这对于位置跟踪非常有用。
import os fd = os.open("data.bin", os.O_RDONLY) # Initial position pos = os.lseek(fd, 0, os.SEEK_CUR) print(f"Initial position: {pos}") # 0 # Read some data os.read(fd, 10) # Check new position pos = os.lseek(fd, 0, os.SEEK_CUR) print(f"After reading 10 bytes: {pos}") # 10 # Seek and verify os.lseek(fd, 5, os.SEEK_SET) pos = os.lseek(fd, 0, os.SEEK_CUR) print(f"After seeking to 5: {pos}") # 5 os.close(fd)
这演示了在操作之间获取当前位置。无论之前的 seek 或读取操作如何,该技术都有效。
这在实现需要跟踪位置的复杂文件解析算法时特别有用。
错误处理
os.lseek 可能会为无效操作引发 OSError。此示例显示了针对各种边缘情况的正确错误处理。
import os try: # Invalid file descriptor os.lseek(999, 0, os.SEEK_SET) except OSError as e: print(f"Error with bad fd: {e}") try: # Seek before start fd = os.open("data.bin", os.O_RDONLY) os.lseek(fd, -1, os.SEEK_SET) except OSError as e: print(f"Error seeking before start: {e}") finally: os.close(fd) try: # Directory seek (invalid) fd = os.open(".", os.O_RDONLY) os.lseek(fd, 10, os.SEEK_SET) except OSError as e: print(f"Error seeking in directory: {e}") finally: os.close(fd)
这显示了三种常见的错误情况:无效的描述符、无效的偏移量以及在目录中定位(不支持)。
在使用 lseek 等底层文件操作时,始终处理潜在的 OSError 异常。
安全注意事项
- 文件描述符: 确保有效的描述符以防止错误
- 边界检查: 验证偏移量以避免无效的 seek
- 并发访问: 其他进程可能会在操作之间修改文件
- 资源泄漏: 始终正确关闭文件描述符
- 平台差异: 行为可能因操作系统而异
最佳实践
- 谨慎使用: 尽可能首选高级文件对象
- 检查返回值: 验证 seek 后的新位置
- 处理错误: 捕获 OSError 以实现稳健的操作
- 记录位置: 清楚地跟踪文件位置的更改
- 清理: 在 finally 块中关闭描述符
资料来源
作者
列出所有 Python 教程。