14

我在 Windows 64 位上使用 Python 3.3.0。

我有一个如下所示的文本文件:(请参阅 mediafire 的下载链接底部)

hello

-data1:blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah


-data2:blah blah blah blah blah blah blah blah blah blah blah
-data3: Empty

-data4: Empty

我试图在文件中导航,因此我.tell()用来确定我的位置。但是,当阅读如下所示的文件行时,我得到了一个非常奇怪的结果:

f=open("test.txt")
while True:
    a = f.readline()
    print("{}    {}".format(repr(a),f.tell()))
    if a == "":
        break

结果:

'hello\n'    7
'\n'    9
'-data1:blah blah blah blah blah blah blah blah blah blah blah blah blah blah bl
ah blah\n'    18446744073709551714
'\n'    99
'\n'    101
'-data2:blah blah blah blah blah blah blah blah blah blah blah\n'    164
'-data3: Empty\n'    179
'\n'    181
'-data4: Empty'    194
''    194

第三行的 18446744073709551714 是怎么回事?尽管它看起来像是一个不可能的值,但它f.seek(18446744073709551714)显然是一个可以接受的值,它显然确实把我带到了第 3 行的末尾。虽然,我似乎无法弄清楚为什么。

编辑:以二进制模式打开没有问题tell()

f=open("test.txt","rb")
while True:
    a = f.readline()
    print("{}    {}".format(repr(a),f.tell()))
    if a == b"":
        break

结果:

b'hello\r\n'    7
b'\r\n'    9
b'-data1:blah blah blah blah blah blah blah blah blah blah blah blah blah blah b
lah blah\r\n'    97
b'\r\n'    99
b'\r\n'    101
b'-data2:blah blah blah blah blah blah blah blah blah blah blah\r\n'    164
b'-data3: Empty\r\n'    179
b'\r\n'    181
b'-data4: Empty'    194
b''    194

test.txt 文本文件可在此处下载,只有 194 个字节:http ://www.mediafire.com/?1wm4lujb2j48y23

4

1 回答 1

13

这是由 UNIX 样式的行尾引起的记录行为:

file.tell()

返回文件的当前位置,如stdio's ftell()

注意:在 Windows 上,读取带有 Unix 样式行尾的文件时,tell()可能会返回非法值(在 之后)。fgets()使用二进制模式('rb')来规避这个问题。


以上文档取自python2.7.4文档。python3 的文档发生了一些变化,因为现在有一个处理 I/O 的类的层次结构,我找不到这些信息。您的测试表明行为并没有改变。此外,python3.3 的源代码在XXX Windows support below is likely incomplete调用的函数之前有注释tell


python bug tracker 中存在与此相关的问题,Catalin Iacob 的最终评论是:

我试图重现这一点,在我的磁盘上选择了一个文件,确实我得到了一个负数,但该文件有 Unix 行结尾。这记录在http://docs.python.org/2/library/stdtypes.html#file.tell 所以可能没有什么可做的。

至于 Armin 在 msg180145 中的报告,尽管它不直观,但这与 ftell 在 Windows 上的行为相匹配,如 http://msdn.microsoft.com/en-us/library/0ys3hc0b%28v=vs.100的备注部分所述%29.aspx。文件对象上的 tell() 方法被明确记录为匹配 ftell 行为:“返回文件的当前位置,如 stdio 的 ftell()”。因此,即使它根本不直观,最好保持原样。在 Python3 和 Python 2.7 上使用 io.open 打开时,tell() 返回直观的非零位置,因此无论如何它在未来都是固定的。

所以这似乎是一个“不会修复”的错误。有人可能应该打开一个问题(评论了这个问题),因为在 python3 文档中根本没有提到这个事实。


根据Antoine Pitrou的说法, python3 根本不使用ftell(),因此这似乎是一个不同的错误。此外,该错误在 python3.2.3 中不可重现,并且可能是在修复此问题时引入的(至少,这是我能找到的对tell()3.2.3 和 3.3 之间实现的唯一更改)


最后编辑:根据io模块文档,该tell方法不返回自文件开头以来的字节数。返回的值是一个“不透明的数字”,这意味着您可以使用它的唯一方法是将它传递seek给以返回该位置。其他操作没有意义。在 python3.2.3 之前返回的值是您所期望的这一事实只是一个实现细节。

请注意,文档这一部分中的信息完全是错误的,希望将来会修复它。

于 2013-04-10T19:46:33.537 回答