【问题标题】:getting a significant offset from file.tell() using iterators使用迭代器从 file.tell() 获得显着偏移
【发布时间】:2018-03-24 19:22:59
【问题描述】:

看着 file.tell(),我期待它给我一个可以与 file.seek() 一起使用的位置。但我不确定如何在实践中做到这一点,因为 tell() 似乎从一开始就将我指向文件的末尾。

这是一些测试数据:

i am line 1
i am line 2
i am line 3

还有程序:

with open("./test_tell.txt") as fi:
    for line in fi:
        seekto = fi.tell()
        print "position:%d" % fi.tell()
        print(line)

    #we're at the end
    fi.seek(seekto)
    print("seekto:%s" % fi.read())

    fi.seek(seekto-5)
    print("seekto-5:%s" % fi.read())
输出:
position:35
i am line 1

position:35
i am line 2

position:35
i am line 3
seekto:
seekto-5:ine 3

请注意我是如何从头开始到 35,文件结尾的?我怎样才能使迭代器只前进到每一行的末尾,以便tell 实际上有助于知道我在文件中的位置?我感觉到整个文件被读取为优化,这就是为什么 tell 把我放在最后。

我关心的原因是我正在开发一个基于状态机的程序,该程序通过一个大文件运行。出于调试目的,我想呈现一个包含n-lines back、当前行和 n-lines ahead 的窗口。希望通过打开同一个文件的不同文件来寻求使用tell位置来读取。这是行不通的,因为 tell 总是指向结尾。

Python 2.7,以防文件语义发生变化。

【问题讨论】:

  • I/O 被缓冲,所以ftell 会给出错误的结果。
  • 在 python 3 中不起作用:混合文件迭代器和 ftell 不起作用。
  • 甚至打开非缓冲open("./test_tell.txt", "r", 0),或逐行缓冲open("./test_tell.txt", "r", 1),都不起作用?无论如何,当我尝试时它没有,仍然是 35。
  • 在不先读取所有 eol 字符的情况下,如何获得 ahead 行数?但无论如何:如果您想知道当前位置,为什么不记录读取的 bytes 计数?
  • @ekhumoro 不确定您所说的第一位是什么意思 - 如前所述,我打算打开第二个文件并寻找当前位置,然后提前读取。至于你的建议 - 是的,我同意如果我自己做簿记它会起作用,但是...... tell 似乎适合我的用例。这只是为了调试。还有一点好奇——尽管我知道缓冲是如何导致这种情况的,但捕捉 Python 代码以意想不到的方式表现是最不寻常的。

标签: python python-2.7 file-io


【解决方案1】:

您的示例不会触发 Python 2 的错误,但会失败,因为可能出于性能原因使用迭代器进行读取 缓冲

大多数时候,当您逐行阅读时,您并不关心文件位置(更一般地说:您不关心文本文件中的文件位置)

所以文件在 1 次操作中被读取,留下文件的结束偏移量。

请注意,Python 3 更严格:在行上迭代后使用tell 会出现异常。

OSError: telling position disabled by next() call

一种方法是

  • 二进制模式下打开文件(Windows,否则,你会因为回车字符而发生变化)
  • 通过添加当前行的长度来读取和计算位置

我的代码:在 python 2 和 python 3 中工作(需要解码以摆脱字节表示以做得更好):

with open("./text.txt","rb") as fi:
    current_offset = 0
    line_pos=[]
    for line in fi:
        line_pos.append(current_offset)
        current_offset += len(line)
        print(line)

    fi.seek(line_pos[1])
    print("seekto:%s" % next(fi))

结果:

b'i am line 1\r\n'
b'i am line 2\r\n'
b'i am line 3\r\n'
seekto:b'i am line 2\r\n'

请注意,我成功地在第二行的开头寻找,所以next(fi) 阅读了第二行。

当然,仍然可以将这些行存储在list 中,除非它太大,在这种情况下,这种方法有一些好处(即:如果文件没有被另一个进程写回,则该行偏移量信息需要更新)

【讨论】:

  • 工作得很好,txs。因为我只关心当前的偏移量,current_offset += len(line) 就足够了。不确定这对实际代码有多大用处,但能够在故障排除期间了解大文件中的周围数据是很好的。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
相关资源
最近更新 更多