6

Windowsで(または)アクセス許可で開かれたファイルのwrite()直後にファイルが更新されないようです。read()r+r+b

testfile.txt現在のディレクトリに次の内容のファイルがあると仮定します。

This is a test file.

次のコードを実行します。

with open("testfile.txt", "r+b") as fd:
    print fd.read(4)
    fd.write("----")

This私はコードがファイルの内容をこれに印刷して更新することを期待します:

This----a test file.

これは、少なくともLinuxでは正常に機能します。ただし、Windowsで実行すると、メッセージは正しく表示されますが、ファイルは変更されません。これは、write()が無視されているようです。ファイルハンドルを呼び出すtell()と、位置が更新されていることが示されますが(前後4)、ファイルは変更されていません。write()8

fd.seek(4)ただし、行の直前に明示を置くと、write()すべてが期待どおりに機能します。

Windowsでこの動作をする理由を知っている人はいますか?

参考までに、NTFSパーティションを備えたWindows7でPython2.7.3を使用しています。

編集

コメントに応えて、私は両方を試しましr+brb+-公式のPythonドキュメントは、前者が標準的であることを示唆しているようです。

fd.flush()私はさまざまな場所に電話をかけ、次のようにread()との間に電話をかけます。write()

with open("testfile.txt", "r+b") as fd:
    print fd.read(4)
    fd.flush()
    fd.write("----")

...次の興味深いエラーが発生します。

IOError: [Errno 0] Error

編集2

同様の問題を説明するこの投稿flush()に私を導いたので、間接的にその追加は助けになりました。コメント投稿者の1人が正しければ、基盤となるWindowsCライブラリのバグです。

4

4 に答える 4

6

Pythonのファイル操作は、libcCファイルIO関数を使用して内部的に実装されているため、規則に従う必要があります。

cplusplusのfopenmanページまたはfopenページからの引用

追加用に開いているファイル(「+」記号を含むファイル)で、入力操作と出力操作の両方が許可されている場合、書き込み操作とそれに続く書き込み操作の間にストリームをフラッシュ(フラッシュ)または再配置(fseek、fsetpos、巻き戻し)する必要があります。ファイルの終わりに到達しなかった読み取り操作または読み取り操作とそれに続く書き込み操作。

要約すると、書き込み後にファイルを読み取る必要がある場合はfflush、バッファを使用する必要があり、読み取り後の書き込み操作の前に、のようにfseek、を付ける必要があります。fd.seek(0, os.SEEK_CUR)

したがって、コードスニペットを次のように変更するだけです。

with open("test1.txt", "r+b") as fd:
    print fd.read(4)
    fd.seek(0, os.SEEK_CUR)
    fd.write("----")

この動作は、同様のCプログラムの動作と一致しています。

#include <cstdio>
int main()
{   
    char  buffer[5] = {0};
    FILE *fp = fopen("D:\\Temp\\test1.txt","rb+");
    fread(buffer, sizeof(char), 4, fp);
    printf("%s\n", buffer);
    /*without fseek, file would not be updated*/
    fseek(fp, 0, SEEK_CUR); 
    fwrite("----",sizeof(char), 4, fp);
    fclose(fp);
    return 0;
}
于 2013-01-11T14:15:30.143 に答える
2

これは、基盤となるWindowsライブラリ(個人的にはエラーだと思います)の動作によるものであり、Pythonには何の問題もないようです。flush()読み取りと書き込みの間に呼び出しを追加すると(これは明らかに良い習慣です)、このブログ投稿IOErrorで説明したのと同じ問題である、ゼロのerrnoでを取得しました。

その投稿から、問題に言及し、読み取りから書き込みに変更するたびに、呼び出しが実際に最良の回避策であると述べているこのPythonの問題を見つけました。seek()flush()

これらすべてを考慮に入れると、Windowsで正常に実行されるように上記のコードを作成するのが最善の方法のようです。

with open("testfile.txt", "r+b") as fd:
    print fd.read(4)
    fd.flush()
    fd.seek(4)
    fd.write("----")

ポータブルコードを書き込もうとしている人にとっては、覚えておくべきことがあるかもしれません。

于 2013-01-11T14:19:45.867 に答える
1

フラッシングを試しましたか?

fd.flush()

書き込みはファイルシステムのキャッシュメカニズムを使用するため、OSに依存します

于 2013-01-11T14:04:48.097 に答える
-1

実装が「r+b」を誤って解釈する可能性はありますか?Afaik "rb +"は、バイナリでの読み取りと書き込み用です。

于 2013-01-11T14:02:34.060 に答える