Pythonでファイルへ書き込みを行う【テキストファイル、バイナリファイル】
- 作成日: 2023-12-25
- 更新日: 2023-12-28
- カテゴリ: Python
Pythonでファイルへ書き込みを行うには?
Pythonでファイルにデータを書き込むには、open()
関数とファイルオブジェクトのメソッド(write()
など)を使います。
この記事ではこれらの関数やメソッドについて解説します。
ファイルへ書き込む手順
ファイルにデータを書き込む手順はPythonに限らず他の言語でも同様になっています。
基本的な流れは以下になります。
- ファイルを開く
- 開いたファイルへデータを書き込む
- ファイルを閉じる
まず関数などでファイルを開き、その開いた結果のストリームやファイルオブジェクトに対してデータを書き込みます。
そしてデータの書き込みが終わったらファイルをちゃんと閉じるようにします。
意外と忘れがちなのがファイルを閉じるということです。
ファイルは開きっぱなしにするとプログラム的な不具合、たとえばファイルが開きっぱなしになるなどが起こることがあります。
ですので使い終わったファイルはちゃんと閉じるのが大事です。
open関数でファイルを開く
Pythonではファイルを開くときはopen()
関数を使います。
open()
はPythonの組み込みの関数で、なにもインポートしなくても使うことができます。
open()
の返り値はオープンモードによって変わります。
オープンモードがテキストファイルの時はio.TextIOWrapper
が、バイナリファイルの書き込みの時はio.BufferedWriter
が返されます。
# これがopen関数のすべてだ!
open(
file, # 開きたいファイルのパス
mode='r', # ファイルのオープンモード
buffering= -1, # バッファリングポリシー
encoding=None, # テキストファイルのエンコーディング
errors=None, # エラー文字列('strict'など)
newline=None, # テキストファイルの改行の指定
closefd=True, # ファイルディスクリプタをクローズするかどうかのフラグ
opener=None # オープナー
)
open()
はキーワード引数がいろいろありますが、よく使うのはfile
, mode
, encoding
の3つだけです。
この3つを押さえておけば大抵の用は足りるかと思います。
file
file
に開きたいパスを指定します。ファイルを開くことが出来ない場合はOSError
が送出されます。
mode
mode
にはオープンモード、つまりファイルをどのようにして開くか? という文字列の指定を書きます。
書き込みに使われるオープンモードは以下になります。
- 'w' ... テキストファイルの書き込みモード
- 'a' ... テキストファイルの追記モード
- 'wb' ... バイナリファイルの書き込みモード
- 'ab' ... バイナリファイルの追記モード
ファイルをテキストファイルとして開き、新規に作成して書き込みしたい場合はw
を使います。
このw
モードの注意点としては、このモードはすでに存在しているファイルであっても中身を空にしてファイルを開くことです。
ですのでうっかり大事なファイルをw
モードで開いて空にしてしまわないように注意しましょう。
ファイルをテキストファイルとして開き、ファイルの末尾に追記したい場合はa
を使います。
このa
はストリームのポジションをファイル末尾にして開きますので、シークなどせずに書き込むだけでファイル末尾に追記できます。
wb
はw
のバイナリファイル版です。
ab
はa
のバイナリファイル版になります。
encoding
エンコーディングはテキストファイルの場合に使われます。
encoding
にUTF-8
を指定するとopen()
はファイルをUTF-8
のエンコーディングで開きます。
CP932
にした場合はCP932
です。
このencoding
は指定しなかった場合は環境のデフォルトのエンコーディングが指定されます。
Windowsの場合はCP932
で、Linuxの場合はUTF-8
です。
ですので、マルチプラットフォームなコードを書きたい場合は、このencoding
を指定するのを忘れないようにしましょう。
たとえばUTF-8
で統一するならencoding
にUTF-8
を指定しておきます。
open('file.txt', 'w', encoding='utf-8')
withを使った自動クローズ
open()
で開いたファイルオブジェクトは使い終わったらクローズしないといけません。
fout = open('file.txt', 'w')
fout.close()
これを自動でやってくれるのがwith
です。
with
を使うとスコープが切れたら自動的にファイルがクローズされます。
ですので明示的なclose()
が必要ありません。
with open('file.txt', 'w') as fout:
pass
上記の場合、fout
がファイルオブジェクトです。
返り値
open()
の返り値はテキストファイルの場合はio.TextIOWrapper
で、バイナリファイルの場合はio.BufferedWriter
が返されます。
これら2つは違うオブジェクトですが、インターフェースがある程度統一されているので、使用者は特に意識しなくても同じ認識で使うことが可能になっています。
with open('file.txt', 'w') as fp:
print(type(fp))
# <class '_io.TextIOWrapper'>
with open('file.txt', 'wb') as fp:
print(type(fp))
# <class '_io.BufferedWriter'>
io.TextIOWrapper — Python 3.12.1 ドキュメント
io.BufferedWriter — Python 3.12.1 ドキュメント
データの書き込み
テキストファイルへの書き込み
テキストファイルを新規作成し、書き込みを行うには以下のようなコードを書きます。
with open('file.txt', 'w', encoding='utf-8') as fout:
fout.write('hello')
上記の場合、file.txt
というファイルが新規作成されてhello
という文字列が書き込まれます。
書き込みにはファイルオブジェクトのwrite()
メソッドを使います。
file.txt
がすでに存在する場合はそのファイルの中身が空になります。
ちなみにfout
という変数はfile output
の略です。この命名は慣例的に使われることがあります。
逆はfin
でfile input
、file pointer
でfp
というのもよく使われます。
テキストファイルへの追記
テキストファイルを開き、追記を行うには以下のようなコードを書きます。
with open('file.txt', 'a', encoding='utf-8') as fout:
fout.write('world')
上記のコードでfile.txt
の中身がhello
だった場合は、追記によって中身がhelloworld
に更新されます。
ファイルが存在しなかった場合は新規でファイルが作成されます。
バイナリファイルへの書き込み
バイナリファイルを新規作成し、書き込みを行うには以下のようなコードを書きます。
with open('file.dat', 'wb') as fout:
fout.write(b'hello')
バイナリファイルのオープンではencoding
は必要ないことに注意してください。
また書き込むデータもb'hello
でb
プリフィックスを付けてバイト列にしていることに注目してください。
file.dat
がすでに存在する場合はそのファイルの中身が空になります。
バイナリファイルへの追記
バイナリファイルへ追記を行うには以下のようなコードを書きます。
with open('file.dat', 'ab') as fout:
fout.write(b'world')
file.dat
の中身がhello
だった場合は追記によって中身がhelloworld
に更新されます。
ファイルが存在しなかった場合は新規作成されます。
バッファのフラッシュ
ファイルオブジェクトはバッファリングと言って、データをある程度溜めてから一括で処理するということを行うことがあります。
この「一括で処理する」ことを「フラッシュ」と言ったりもします。
書き込みの場合は「一括で書き込む」という意味になるかと思います。
このフラッシュをマニュアルで行いたい場合は、ファイルオブジェクトのメソッドのflush()
を使います。
以下はフラッシュを使ったサンプルです。
import time
with open('file.dat', 'wb') as fout:
for i in range(10):
fout.write(b'1')
fout.flush()
time.sleep(1)
上記のコードを実行すると、1秒ごとにfile.dat
にデータが書き込まれてフラッシュされます。
プログラムの実行中にfile.dat
の中身をcat
やtype
などで見ると、中身が刻々と変わっていくのがわかると思います。
このフラッシュの概念は標準ファイルオブジェクトにも存在します。
標準ファイルオブジェクトはsys.stdout
やsys.stderr
などです。
print()
は内部でsys.stdout
にデータを書きこんでいますので、print()
でバッファをフラッシュしたい場合はsys.stdout.flush()
などを実行するといいでしょう。
あるいはprint('Hello', flush=True)
でもフラッシュを実行できます。
io.BufferedWriter
の場合は、フラッシュのタイミングは以下になります。
- 保留している全てのデータに対してバッファが足りなくなったとき
- flush()が呼ばれたとき
- seek()がリクエストされたとき
- ファイルオブジェクトが閉じられたり破棄されたとき
io.BufferedWriter — Python 3.12.1 ドキュメント
エラーの処理
open()
でエラーを処理したい場合は例外をキャッチします。
open()
はOSError
を継承した例外を送出しますので、これでハンドリングできます。
たとえばファイルが存在しなかった場合はFileNotFoundError
が送出されます。
try:
with open('nothing.dat', 'r') as fin:
pass
except FileNotFoundError as e:
print(e)
# [Errno 2] No such file or directory: 'nothing.dat'
しかし、書き込みも追記もファイルを新規作成しますので、このエラーになることはない気がします。
よくあるのはパーミッションエラーでしょう。
try:
with open('permission.dat', 'w') as fin:
pass
except PermissionError as e:
print(e)
# [Errno 13] Permission denied: 'permission.dat'
パーミッションエラーはファイルに対する操作の権限がない時に発生します。
たとえばファイルの所有者が他のユーザーで、そのユーザーのファイルに対する書き込み権限を持っていない場合は、このようなエラーが出ます。
パーミッションエラーを人為的に発生させたい場合、Ubuntuなどではファイルの所有者をroot
にするとエラーを発生させられます。
もちろんスクリプトの実行はroot
以外で行う必要があります。
$ # permission.dat のファイルの所有者とグループを root に変更
$ sudo chown root:root permission.dat
大量データの書き込み
データ量が多い場合はバッファにデータを溜めてそれを一気に書き込むか、あるいは分割されているデータを随時書き込んでいくかになります。
ですがバイナリのファイルオブジェクトはデフォルトでバッファリングをしますので、わざわざバッファを作ってそれにデータを溜めなくても、勝手にバッファリングしてくれる理屈になります。
よってメモリを節約したい場合は随時書きこんで行った方がいいのかもしれません。
# 大量データの書き込み
with open('file.dat', 'wb') as fout:
for _ in range(100000):
fout.write(b'1')