システム開発を続けていると、扱うデータ量が多くなり、テキストファイルからデータを読み込んだり、またテキストファイルにデータを書き込んだりといったことをする必要が出てきます。
例えば設定ファイルをテキストに切り出しておいて、必要なときに読み込んだり、バグが発生したときのエラーログをlogファイルに出力したり、といったことが考えられます。
ここでは「ファイルへの読み書きってどうやるの?」という疑問にお答えしつつ、ファイルI/Oについて解説していきます。
テキストファイルの読み込み
まずはテキストファイルの読み込みから見ていきましょう。
基礎的なファイル読み込み
ファイルを読み込むには次の3つの手順を踏む必要があります。
- ファイルを開く
- 内容を読み込む
- ファイルを閉じる
ファイルを開くにはopen()関数、読み込みにはread()メソッド、閉じるにはclose()メソッドと、それぞれのステップに対応した関数やメソッドがあるので分かりやすくなっています。
では実際にテキストファイルを読み込んでみましょう。今回は下の内容が記述されているファイルを読み込みます。
[setting.ini]ファイル
PARAM1 = True
PARAM2 = 100
PARAM3 = abc
file = open("./setting.ini")
text = file.read()
file.close()
print(text)
[出力結果]
PARAM1 = True
PARAM2 = 100
PARAM3 = abc
まずopen()でsetting.iniファイルを開いています。次にfile.read()でファイルの中身を読み込み、file.close()でファイルを閉じます。最後にprint()で読み込んだ内容を出力しています。
今回はopen()でファイルパスのみ指定しましたが、他によく使う引数としてmodeとencodingがあります。
open(ファイルパス, mode=”rt”, encoding=None)
modeはファイルの開き方を指定します。例えば読み取り専用なのか、書き込み可なのか、ファイルがすでに存在する場合は上書きなのか、追記なのか、などを指定できます。
modeの種類
mode | 説明 |
---|---|
r | 読み込み専用で開きます。(デフォルト) |
w | 書き込み可能で開きます。既にファイルが存在する場合は上書きします。 |
a | 書き込み可能で開きます。既にファイルが存在する場合は追記します。 |
x | ファイルが存在しないことを確認してから、書き込み可能で開きます。 |
t | テキストモードで開きます。(デフォルト) |
b | バイナリモードで開きます。 |
encodingは開くファイルのエンコーディングを指定できます。読み込もうとしたファイルと指定したエンコーディングが異なるとエラーになります。指定できるエンコーディングには「utf_8」「euc_jp」「shift_jis」などがあります。デフォルトはプラットフォームと同じエンコーディングを使います。例えばMacOSなら(特に変えていなければ)UTF-8がデフォルトになります。localeモジュールのgetpreferredencoding()を使うと、現在のプラットフォームのエンコーディングを調べられます。
import locale
print(locale.getpreferredencoding())
[出力結果]
UTF-8
with-asを使ってファイルを読み込む
with-as構文を使うことでもファイルを読み込むことができます。with-asを使った場合は、close()処理を省略できます。
先ほどの例をwith-asを使った例に置き換えてみましょう。
with open("./setting.ini") as file:
text = file.read()
print(text)
ちょっとスッキリしましたね。
open()を使う方が直感的ですが、ファイルの読み書きをより簡潔に記述できるのはwith-asです。好みによって使い分けて問題ありませんが、with-asは、openと違いcloseをつける必要が無いので、基本的にはwith-asを使うことの方が多い印象です。
1行ずつ読み込む
readline()を使うことで、ファイルの内容を1行ずつ読み込むことができます。
with open("./setting.ini") as file:
i = 1
while True:
include_break_line = file.readline() #改行が含まれた行
line = include_break_line.rstrip() #改行を取り除く
if line: #文字が入ってるか確認
print(f'{i}行目:{line}')
i += 1
else:
break
[出力結果]
1行目:PARAM1 = True
2行目:PARAM2 = 100
3行目:PARAM3 = abc
上記の例ではwhile Trueで無限ループしながら、readline()で先頭から1行ずつ行を読み込んでいます。
読み込んだ行は末尾に改行文字が含まれているので、rstrip()で改行を取り除き、ifで文字が入っているかどうかを確認し、入っていれば出力し、入っていなければ無限ループを抜け出し、処理を終了しています。
テキストファイルへの書き込み
次にテキストファイルへの書き込み方法を見ていきましょう。ファイル書き込みはファイルをオープンする時に書き込み可能なモードで開く必要があります。
基本的なファイル書き込み
ファイルのopen()やclose()は読み込みの時と同じです。ファイル書き込みにはwrite()を使います。
file = open("./setting.ini", mode="a")
file.write("PARAM4 = ぱらめーた\n")
file.close()
[setting.ini]ファイル
PARAM1 = True
PARAM2 = 100
PARAM3 = abc
PARAM4 = ぱらめーた
上記の例ではmodeにaを指定したので、追記モードでの書き込みになっています。
書き込むテキストの最後に\nとありますが、この改行文字を入力しないと前回書き込んだ行の続きから書き込んでしまうので、必要に応じて入れるようにしましょう。
今回は追記モードでの書き込みでしたが、mode=”w”を指定すると上書きになります。
file = open("./setting.ini", mode="w") #modeをwに変更
file.write("PARAM4 = ぱらめーた\n")
file.close()
[setting.ini]ファイル
PARAM4 = ぱらめーた
setting.iniに元々書かれていたテキストが消え、新しく書き込んだテキストのみになりました。mode=”w”で書き込む場合は注意しましょう。
with-asを使ってテキストを書き込む
書き込みでもwith-asを使うことができます。close()が不要なのも読み込みのときと同じです。
with open("./setting.ini", mode="a") as file:
file.write("PARAM4 = ぱらめーた\n");
ファイルが存在するかチェックする
読み込みでも書き込みでも、まず始めにopen()でファイルを開きますが、指定したパスにファイルが存在しない場合はエラーになってしまいます。
with open('./setting.txt') as file: #存在しないファイル
text = file.read()
print(text)
[出力結果]
FileNotFoundError: [Errno 2] No such file or directory: './setting.txt'
ファイルが存在するかどうかを確認する必要がある場合は、osモジュールのpath.exists()を使います。
import os
print(os.path.exists('./setting.txt')) #存在しない
print(os.path.exists('./setting.ini')) #存在する
[出力結果]
False
True
また、ファイルを作成したいパスにディレクトリが存在しない場合は、os.makedirs()でフォルダを作成できます。
os.path.exists()はディレクトリが存在しない場合もFalseを返してくれるので、これを利用して「ディレクトリがない場合は作成してから書き込み処理をする」ことができます。
import os
if not os.path.exists('./abc/'):
os.makedirs('./abc/')
with open('./abc/sample.txt', 'a') as file:
file.write('write to sample.txt\n')
[./abc/sample.txt]
write to sample.txt