【发布时间】:2019-01-18 22:29:54
【问题描述】:
f.seek(500000,0) 在到达第 500000 个之前是否会遍历文件的所有前 499999 个字符?
换句话说,f.seek(n,0) 的阶数是 O(n) 还是 O(1)?
【问题讨论】:
标签: python file io big-o fseek
f.seek(500000,0) 在到达第 500000 个之前是否会遍历文件的所有前 499999 个字符?
换句话说,f.seek(n,0) 的阶数是 O(n) 还是 O(1)?
【问题讨论】:
标签: python file io big-o fseek
您需要更具体地了解f 是什么类型的对象。
如果f 是存储在磁盘上的文件的普通io module 对象,则必须确定是否正在处理:
BytesIO 或 TextIO 对象第一个选项只是使用lseek system call 重新定位文件描述符位置。如果这个调用是 O(1) 取决于操作系统和你有什么样的文件系统。对于带有 ext4 文件系统的 Linux 系统,lseek is O(1)。
缓冲区只是清除缓冲区if your seek target is outside of the current buffered region 并读入新的缓冲区数据。这也是 O(1),但固定成本更高。
对于文本文件,由于可变字节长度编解码器和行尾翻译意味着您不能总是将二进制流位置映射到文本位置而不从头开始扫描,因此事情会更加复杂。该实现不允许非零当前位置或末端相对寻道,并且最好尽量减少为绝对寻道读取的数据量。 Internal state shared with the text decoder 跟踪 recent 'safe point' to seek back to 并向前读取到所需位置。最坏的情况是 O(n)。
内存中的文件对象实际上只是长的、可寻址的数组。查找是 O(1),因为您可以更改当前位置指针值。
还有许多其他类似文件的对象可能支持也可能不支持查找。他们如何处理查找取决于实现。
zipfile module 支持查找以只读模式打开的 zip 文件,并且查找位于当前缓冲区覆盖的数据部分之前的点需要完全重新读取数据并解压缩到所需的数据点,追求需要从当前位置读取,直到到达新位置。 gzip、lzma 和 bz2 模块都使用same shared implementation,也使用starts reading from the start if you seek to a point before the current read position(并且没有更大的缓冲区可以避免这种情况)。
chunk module 允许在块边界内搜索并委托给底层对象。如果底层文件查找操作为 O(1),则这是一个 O(1) 操作。
等等。所以,这取决于。
【讨论】:
gzip 模块,它与其他压缩格式共享一个通用的基本实现,如果你是,这些必须完全重新读取压缩流寻找当前点之前的点。
gzip 文件本身上获取tell 和seek,而不是在底层解压缩数据上?
gzipfileobj.fileobj。然而,寻找那个对象将读取读取缓冲区的内部状态。
这将取决于 f 的实现。但是,在普通文件系统文件中,它是 O(1)。
如果 python 在文本文件上实现 f,它可以实现为 O(n),因为可能需要检查每个字符以正确管理 cr/lf 对。
f.seek(n,0) 是否给出与读取字符循环相同的结果,并且(取决于操作系统)cr/lf 缩小为 lf 或 lf 扩展为 cr/lf 如果python在压缩流上实现f,那么顺序将是b O(n),因为解压可能需要一些块的工作和解压。
【讨论】:
However, in normal file-system files, it is O(1). 这似乎很不对。
n,但是,我希望 n 足够接近当前偏移量,seek 不会导致任何磁盘访问。
zipfile.ZipFile 确实支持读取时的搜索,它会尝试从当前缓冲区中满足。如果不能,它会回到压缩部分开始并重新读取数据,直到它到达所需的位置。
seek 本身几乎肯定是 O(1),因为任何进一步的工作都可以(并且应该)延迟到读取或写入实际需要新文件位置。如果对文件的下一个操作是关闭,那么执行 O(N) 操作是没有意义的。