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

3 行目の 18446744073709551714 は何ですか? 不可能な値のように見えますがf.seek(18446744073709551714)、どうやら 3 行目の終わりに到達する許容値です。しかし、私はその理由を理解できないようです。

EDIT:バイナリモードで開いても問題はありません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ののように、ファイルの現在位置を返しますftell()

: Windows では、Unix スタイルの行末を持つファイルを読み取るときtell()に、( の後に) 不正な値を返すことがあります。fgets()この問題を回避するには、バイナリ モード ('rb') を使用します。


上記のドキュメントは、python2.7.4 のドキュメントから取得したものです。I/O を処理するクラスの階層があり、この情報を見つけることができないため、python3 のドキュメントが少し変更されました。あなたのテストは、とにかく動作が変わらないことを示しています。また、python3.3 のソース コードには、XXX Windows support below is likely incompleteによって呼び出される関数の前にコメントがありtellます。


これに関連する python バグ トラッカーに問題があり、Catalin Iacob による最後のコメントは次のとおりです。

これを再現しようとして、ディスク上のファイルを選択したところ、実際に負の数が得られましたが、そのファイルには Unix の行末が含まれています。これはhttp://docs.python.org/2/library/stdtypes.html#file.tellに文書化され ているので、おそらく何もする必要はありません。

msg180145 の Armin のレポートに関しては、直感的ではありませんが、これは Windows での ftell の動作と一致します 。 %29.aspx . fileobjects の tell() メソッドは、一致する ftell 動作として明示的に文書化されています: 「stdio の ftell() のように、ファイルの現在位置を返します」。したがって、まったく直感的ではありませんが、おそらくそのままにしておく方がよいでしょう。tell() は、Python3 および Python 2.7 で io.open を使用して 'a' で開くと、直観的なゼロ以外の位置を返すため、将来のために修正されています。

したがって、「修正しない」バグのようです。この事実は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 に答える