Python基礎講座 #18 ファイル読み書き 第2回 (file read, write – vol.2)

読了 10分

今回の講座では、前回の講座に続いてファイルの書き込みについて勉強していきましょう。もし前回の講座をまだ見ていない場合は、下のリンクからまずファイルの読み込みについて勉強してください。

Python基礎講座 #17 ファイル読み書き 第1回 (file read, write – vol.1)

ファイル読み書きモード

モード説明
r読み込み専用モードであり、デフォルトオプションなので省略しても構いません。
w書き込み専用モードであり、同じ名前のファイルがなければ新しいファイルを作成し、あれば上書きをします。上書きをすると既存ファイルのデータがすべて消えるので注意してください。
x書き込み専用モードですが、同じ名前のファイルが存在するとエラーを発生させます。wモードの安全モードと考えてください。
a追加モードであり、同じ名前のファイルがなければ新しいファイルを作成し、あれば末尾から続けて書き込むモードです。
tテキストモードでデフォルトモードなので省略可能です。
bバイナリモードで、PDFや画像ファイルなど、一般のテキストファイルではなくバイナリで作られたファイルを開く時に使うモードです。
r+読み込みと書き込みを同時にできるモードです。
w+読み込みと書き込みを同時にできるモードです。

ファイルを書き込む方法は、ファイルを読み込む方法とかなり似ています。ファイルを読み込む時と同じく open 関数を使い、modeパラメータに wxa オプションのうち一つを使えば大丈夫です。

まず w オプションを使ってファイル書き込みをやってみましょう。書き込みをするには file オブジェクトが持っている write メソッドを使えば大丈夫です。write メソッドは文字列を引数として受け取って、ファイルに書き込む役割をします。

Pythonコード
with open(file='out.txt', mode='w', encoding='utf8') as file:
    file.write('line one')
    file.write('line two')
out.txt
line oneline two

2行を書こうとしたのに1行に入力されてしまう問題が発生しました。write メソッドは改行をしないため、こういう問題が発生するのです。下のコードのように改行(\n)キャラクターを入れてあげれば問題が解決します。

Pythonコード
with open(file='out.txt', mode='w', encoding='utf8') as file:
    file.write('line one\n')
    file.write('line two\n')
out.txt
line one
line two

2行できれいに出力されました。毎回改行キャラクターを入れるのが面倒だという方は、下のコードのように print 関数を使えば大丈夫です。help関数を使って print 関数のヘルプを確認してみましょう。

Pythonシェル
help(print)
コンソール出力
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

print関数は end パラメータにデフォルト値として改行キャラクターを持っており、file パラメータに sys.stdout 値をデフォルトとして持っています。sys.stdout とはコマンドプロンプトやターミナルだと考えてください。この file パラメータに引数として file オブジェクトを渡して実行すると、文字列がコンソールに出力されずファイルに書き込まれ、毎回文字列の末尾に改行キャラクターを追加する必要もありません。

Pythonコード
with open(file='out.txt', mode='w', encoding='utf8') as file:
    print('line 1', file=file)
    print('line 2', file=file)
out.txt
line 1
line 2

コードを再実行するたびに、ファイルに保存されていたテキストはすべて消えて新しいテキストが入力されるのが分かりますが、w モードを使う場合「out.txt」という名前のファイルがなければ新しいファイルを作成し、すでに存在する場合は新しいテキストで上書きをするため、既存のテキストはすべて消えるという点を必ず覚えておいてください。間違ってデータをすべて消し飛ばすことがないように注意してください。

今度は国情報が入っている辞書の値をファイルに書いてみましょう。

Pythonコード
countries = [
    {'国名': '日本', '首都名': '東京', '地域名': 'アジア'},
    {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'},
    {'国名': '中国', '首都名': '北京', '地域名': 'アジア'},
]

with open(file='country.txt', mode='w', encoding='utf8') as file:
    for country in countries:
        line = '国名: {国名}, 首都名: {首都名}, 地域名: {地域名}\n'.format(**country)
        file.write(line)
country.txt
国名: 日本, 首都名: 東京, 地域名: アジア
国名: 韓国, 首都名: ソウル, 地域名: アジア
国名: 中国, 首都名: 北京, 地域名: アジア

データがファイルにきちんと保存されているのが確認できました。このようにプログラムで定義したリストや辞書をテキストファイルに保存するには str 関数を使えば大丈夫です。

Pythonコード
countries = [
    {'国名': '日本', '首都名': '東京', '地域名': 'アジア'},
    {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'},
    {'国名': '中国', '首都名': '北京', '地域名': 'アジア'},
]

with open(file='country.txt', mode='w', encoding='utf8') as file:
    file.write(str(countries))
country.txt
[{'国名': '日本', '首都名': '東京', '地域名': 'アジア'}, {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'}, {'国名': '中国', '首都名': '北京', '地域名': 'アジア'}]

ファイルにリストオブジェクトがコードと同じ形式で保存されました。このように保存されたオブジェクトをもう一度読み込むと、Pythonインタプリタはこれをリストオブジェクトとして認識せず、文字列として返します。確認してみましょう。

Pythonコード
countries = [
    {'国名': '日本', '首都名': '東京', '地域名': 'アジア'},
    {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'},
    {'国名': '中国', '首都名': '北京', '地域名': 'アジア'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    print(type(result))
コンソール出力
<class 'str'>

ファイルに保存されたデータをプログラムで読み込んで再び使いたい時は、下のコードのように eval 関数を使ってリストや辞書オブジェクトに変換して使うことができます。

Pythonコード
countries = [
    {'国名': '日本', '首都名': '東京', '地域名': 'アジア'},
    {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'},
    {'国名': '中国', '首都名': '北京', '地域名': 'アジア'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    result = eval(result)
    print(type(result))
コンソール出力
<class 'list'>

リストオブジェクトに変換されたので、上で定義した辞書をリストと同じように使うことができます。

Pythonコード
countries = [
    {'国名': '日本', '首都名': '東京', '地域名': 'アジア'},
    {'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'},
    {'国名': '中国', '首都名': '北京', '地域名': 'アジア'},
]

with open(file='country.txt', mode='r', encoding='utf8') as file:
    result = file.read()
    result = eval(result)
    for country in result:
        print(country)
コンソール出力
{'国名': '日本', '首都名': '東京', '地域名': 'アジア'}
{'国名': '韓国', '首都名': 'ソウル', '地域名': 'アジア'}
{'国名': '中国', '首都名': '北京', '地域名': 'アジア'}

今度は mode パラメータの x オプションについて見ていきましょう。先ほど x オプションは w モードの安全モードのようなものだと説明しましたが、このオプションを使うと、同じ名前のファイルがあるとエラーを発生させてくれるため、誤ってデータを消し飛ばす問題を防ぐことができます。

Pythonコード
with open(file='country.txt', mode='x', encoding='utf8') as file:
    file.write('新しいデータ')
コンソール出力
---------------------------------------------------------------------------
FileExistsError                           Traceback (most recent call last)
<ipython-input-9-e897f33b1472> in <module>
----> 1 with open(file='country.txt', mode='x', encoding='utf8') as file:
      2     file.write('新しいデータ')

FileExistsError: [Errno 17] File exists: 'country.txt'

FileExistsError エラーが発生してプログラムが終了したのが分かります。

今度は mode パラメータの a オプションについて見ていきましょう。 a オプションは追加モードで、同じ名前のファイルがなければ新しいファイルを作成し、同じ名前のファイルがある場合は w オプションのように上書きをするのではなく、ファイルが開かれるとカーソルがファイルの一番末尾に位置し、カーソルがある部分から続けて書き込みをします。

append.txt
既存データ

1行のテキストが入っている append.txt ファイルに a オプションを使ってファイルにテキストを追加してみましょう。

Pythonコード
with open(file='append.txt', mode='a', encoding='utf8') as file:
    file.write('追加したテキスト')
append.txt
既存データ追加したテキスト

追加したテキストが既存データと同じ行に入力されてしまいましたが、ファイルにテキストを追加する時は、既存テキストの最後の行に改行があるか確認し、ない場合は次のように追加するテキストの先頭に改行キャラクターを追加してください。

Pythonコード
with open(file='append.txt', mode='a', encoding='utf8') as file:
    file.write('\n追加したテキスト')
append.txt
既存データ
追加したテキスト

一般のテキスト読み書きについての勉強はここまでにして、CSV、JSON、YAML、EXCELなどの特殊フォーマットのファイルを扱う方法は別の講座で扱うことにします。

次回はエラーと例外処理を取り上げます。

X