Python file.tell()给出了奇怪的数字?

Eri*_*ric 11 python python-3.x

我在Windows 64bit上使用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
Run Code Online (Sandbox Code Playgroud)

我正试图浏览文件,因此我.tell()用来弄清楚我的位置是什么.但是,当读取如下所示的文件行时,我得到一个非常奇怪的结果:

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

结果:

'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
Run Code Online (Sandbox Code Playgroud)

第三行的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
Run Code Online (Sandbox Code Playgroud)

结果:

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
Run Code Online (Sandbox Code Playgroud)

test.txt文本文件可以在这里下载,只需194个字节:http://www.mediafire.com/?1wm4lujb2j48y23

Bak*_*riu 11

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

file.tell()

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

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


以上文档摘自python2.7.4文档.python3的文档稍有改动,因为现在有一个处理I/O的类层次结构,我找不到这些信息.您的测试显示该行为无论如何都没有改变.另外python3.3的源代码在调用XXX Windows support below is likely incomplete函数之前有一个注释tell.


与此相关的python bug跟踪器存在一个问题,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.fileobjects上的tell()方法被明确记录为匹配的ftell行为:"返回文件的当前位置,如stdio的ftell()".所以即使它根本不直观,最好还是保持原样.当使用i3.on时,tell()在Python3和Python 2.7上使用'a'打开时返回直观的非零位置,因此无论如何它都是固定的.

所以它似乎是一个"wontfix"错误.有人应该打开一个问题(评论问题)因为python3文档中根本没有提到这个事实.


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


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

请注意,文档节中的信息是完全错误的,希望将来可以修复.