
目次
はじめに
Python 入出力時に、読み込みと書き込みを行う「読み書き」モード ( r+/w+/a+ ) の挙動について検証を行い、まとめました。
経緯
Python の open 関数に渡す mode 引数に 'rw' を指定したところ、下記エラーが発生してしまいました。
ValueError: must have exactly one of create/read/write/append mode.
Python では「読み書き」モードが存在しないのか?と思って調べまわった結果、Python の mode 引数は
c の fopen の mode 引数に準拠しており、「読み書き」モードは "rw" でなく、"r+", "w+", "a+"
のいずれかを使う必要があるという事でした。
管理人の記憶では、c の fopen も読み書きモードは "rw" だったような気がしていたのですが、ネット上を調べると、"rw" を使っている例がごく少数散見されるだけのため、おそらく c が標準化される際に記述が変更されたのではないかと想像しています。管理人の知識は既に化石的なものなのか・・・。
というわけで、気を取り直して r+ / w+ / a+ の各モードの動作の違いを検証し、まとめます。
[検証1]ファイルが存在しない時の挙動
存在しないファイル 'abc.txt' に対して各 mode で open を試みます。
open('abc.txt', mode)
(結果)
- r+: FileNotFoundError: [Errno 2] No such file or directory: 'abc.txt'
- w+, a+: 'abc.txt' が作成される
'r+' の場合は例外が発生しますが、'w+' と 'a+' では空のファイルが作成されます。
[検証2]ファイルポインタの位置確認(1)
'abc.txt' の内容を 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' としておき、下記を実行します。
with open('abc.txt', mode) as f: print(f.tell())
(結果)
- r+: 0
- w+: 0
- a+: 26
'r+' は 0 (先頭)、'a+' は 26 (末尾) となっているのが確認できます。'w+' はファイルが切り詰められているため、0 (先頭 = 末尾) です。
[検証3] ファイルポインタの位置確認(2)
'abc.txt' の内容を 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' としておき、下記を実行します。
with open('abc.txt', mode) as f: print(f.read())
(結果)
- r+: ABCDEFGHIJKLMNOPQRSTUVWXYZ
- w+: 何も表示されない
- a+: 何も表示されない
'r+' は、ファイル先頭から read しています。'a+' は、ファイル末尾から read しますので何も表示されません。'w+' は、ファイルを切り詰めているので何も表示されません。
[検証4] ファイル更新の挙動
'abc.txt' の内容を 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' としておき、下記を実行します。
with open('abc.txt', mode) as f: f.write('abc')
(結果)
- r+: abcDEFGHIJKLMNOPQRSTUVWXYZ
- w+: abc
- a+: ABCDEFGHIJKLMNOPQRSTUVWXYZabc
3種のモードの違いがはっきりと出ました。
'r+' は先頭から上書きで 'abc' を書き込むため、'ABC' が 'abc' に置換されました。
'w+' はファイルを切り詰めてから書き込みますので、文字列全体が置換されました。
'a+' はファイル末尾に書き込むため、末尾文字列が追加されました。
結論
以上をまとめます。
mode
|
概要
|
open() 時の
ポインタ位置
|
ファイルが
存在しない時
|
r+
|
標準的な読み書きモード。
既存のデータを読み書きする。 |
先頭
|
FileNotFoundError
|
w+
|
既存のデータを捨てて新規にデータを読み書きするモード。
ファイルを長さ 0 に切り詰めて
読み書きモードで開く。 |
先頭=末尾
|
作成
|
a+
|
既存のデータの後に新規データを追加書き込みする読み書きモード。 |
末尾
|
作成
|