静かなる名辞

pythonとプログラミングのこと

ファイルオブジェクトのcloseはflushも行う。確実にしたければfsync

 以前、「ファイルオブジェクトのcloseメソッドは同時にflushも行う」ことを知りました。

 どうやらcloseするときは内部でflushメソッドが呼ばれるようです。

このストリームをフラッシュして閉じます。
io --- ストリームを扱うコアツール — Python 3.7.3rc1 ドキュメント

 ということは、「ファイルを閉じた後即座に反映させたいので、flushメソッドを呼んでおく」という操作は必要ないようです。closeすれば同時にflushされるので。

 余談ですが、ファイルオブジェクトのflushを呼べばそれで確実に処理が終わったタイミングでディスクに書かれているか? というと、OS側でバッファリングされるので、保証はされないということらしいです。

operating system - does close() imply flush() in Python? - Stack Overflow

 flushはあくまでも「pythonプロセスからOSにちゃんと渡した」というところまでしか保証しないのでしょうか・・・。

 対策はfsyncと呼ばれるシステムコールを使うことです。pythonでもosモジュールにインターフェースがあります。

参考:ファイル出力したそのデータ、本当にディスクに書き出されてますか? - らっちゃいブログ

Python の ファイルオブジェクト f を使う場合、f の内部バッファを確実にディスクに書き込むために、まず f.flush() を、その後 os.fsync(f.fileno()) を実行してください。
os --- 雑多なオペレーティングシステムインタフェース — Python 3.7.3rc1 ドキュメント

 あ、これはflushしないと駄目なんですね。先にcloseしないので当然か。

import os

with open("sample.txt", "w") as f:
    f.write("hoge")
    f.flush()
    os.fsync(f.fileno())

 このようにすると処理を抜けた時点でディスクに書かれていることが保証されると思います。また、メタデータ更新を行わない(ドキュメントには「強制しない」と書いてあるが、実際にどういう挙動なのかは謎)fdatasyncという類似関数も用意されています。上に載せた参考リンクで紹介されています。