Python中f.seek()的复杂性

Irr*_*ant 7 python io big-o file fseek

f.seek(500000,0)在到达500000th之前,是否会检查文件的所有前499999个字符?换句话说,是f.seek(n,0)O(n)还是O(1)?

Mar*_*ers 12

您需要更具体地了解对象的类型f.

如果f是存储在磁盘上的文件的普通io模块对象,则必须确定是否正在处理:

  • 原始二进制文件对象
  • 一个缓冲区对象,包装原始二进制文件
  • 一个TextIO对象,包装缓冲区
  • 内存BytesIOTextIO对象

第一个选项只是使用lseek系统调用来重新定位文件描述符位置.如果此调用是O(1)取决于操作系统和您拥有的文件系统类型.对于具有ext4文件系统的Linux系统,lseek是O(1).

如果您的搜索目标位于当前缓冲区域之外并且读入新缓冲区数据,缓冲区仅清除缓冲区.这也是O(1),但固定成本更高.

对于文本文件,事情更复杂,因为可变字节长编解码器和行结束转换意味着您无法始终将二进制流位置映射到文本位置而无需从头开始扫描.该实现不允许非零当前位置或最终相对搜索,并且最好最小化为绝对搜索读取多少数据.与文本解码器共享的内部状态跟踪最近的"安全点"以寻找并向前读取到期望的位置.最坏的情况是O(n).

内存中的文件对象实际上只是很长的可寻址数组.寻求是O(1)因为您可以只改变当前位置指针值.

有其他类似文件的对象,可能支持也可能不支持搜索.他们如何处理寻求是依赖于实现的.

  • zipfile模块支持搜索以只读模式打开的zip文件,并寻找位于当前缓冲区覆盖的数据部分之前的点,需要对数据进行完全重新读取和解压缩,直至所需点,从当前位置读取,直到达到新的位置.的gzip,lzmabz2模块都使用同一个共享的实现,也开始从一开始如果你寻求到一个点当前读取位置之前(而且也没有更大的缓冲区,以避免这种情况)读书.

  • chunk模块允许在块边界内进行搜索并委托给底层对象.如果基础文件搜索操作是O(1),则这是O(1)操作.

等等,这取决于.