open関数とファイルオブジェクトとその他もろもろ
初回公開:2017/11/05
最終更新:未
【 目次 】
いつものように環境はwindos10にてテスト
pythonのファイルアクセスについてググってみると
open関数
まず、open関数を使ってファイルをオープン。
f = open(filename, mode)
- filename
- 最初の引数はファイル名の入った文字列です。
- mode
- r:読み出し専用
w:書き込み専用 (同名の既存のファイルがあれば消去される)
a: はファイルを追記用に開く(ファイルに書き込まれた内容は自動的にファイルの終端に追加さる。)
r+:読み書き両用で開く
'b' をつけるとバイナリモードで開く(通常はテキストモード )
mode 引数は省略可能で、省略された場合には 'r' であると仮定される。
改行文字の扱い
プラットフォーム固有の行末記号 (Unix では \n 、Windows では \r\n) をただの \n に変換するのがデフォルトの動作です。
テキストモードの書き込みでは、 \n が出てくる箇所をプラットフォーム固有の行末記号に戻すのがデフォルトの動作です。
このためバイナリファイルをテキストモードで開くとバイナリデータを破壊する恐れがあり危険。
Unix では、 'b' を追加しても何も影響がない
デフォルトのエンコード
エンコーディングが指定されなければ、デフォルトはプラットフォーム依存です (open() を参照してください) 。
open関数のリファレンス
公式ドキュメントのopen関数は
- 2. 組み込み関数 — Python 2.7.13 ドキュメント
open(name[, mode[, buffering]])
- 2. 組み込み関数 — Python 3.6.1 ドキュメント
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
Python 3ではname(filename)やmode引数の他に多くの引数を指定する事ができ、encoding引数を使って文字コードのエンコードを指定する事ができる。
従ってPython 3ではエンコードの指定は簡単だが、python2の場合はencoding引数が用意されていない。
python2の場合はどうするのだろうか?
ファイル入出力の簡単なサンプルコード
まず、半角文字テキストファイルの入出力のサンプルコードを示す。
半角テキストのファイル入出力 - python2
# 半角テキストのファイル出力 b_str=""" sabcdef 1234567 xya123 """ f = open("asc_sample.txt",'w') f.write(b_str) f.close() # 半角テキストのファイル入力 f = open("asc_sample.txt",'r') str=f.read() f.close() print str
実行結果
sabcdef 1234567 xya123
open関数はファイルオブジェクトを返す。
print f.__class__.__name__
実行結果
file
エンコードされたファイルの扱いと標準のopen関数
open関数を使ってアスキーテキストを読み込んで表示させる事は可能だが、 ではutf-8等のエンコードされたファイルの入出力はどうなるだろう。
python3
以下の内容をテキストエディタで入力してutf-8で保存
uni_sample.txt
あいうえお かきくけこ abcd1234
前述のとおり、python3ではopen関数にencoding引数が用意されているので open関数のfilename引数にutf-8で保存したファイルを指定して
f = open("uni_sample.txt",'r',encoding="utf-8") str=f.read() f.close() print(str)
実行結果
あいうえお かきくけこ abcd1234
python2
python2にはopen関数にencoding引数が用意されていない。
とりあえず、encoding引数を指定せずにプログラムを実行してみる。
f = open("uni_sample.txt",'r') str=f.read() f.close() print str
実行すると
実行結果
縺ゅ>縺・∴縺・ 縺九″縺上¢縺・ abcd1234
文字化けを起こしてしまう。
readメソッドの戻り値を格納したstr変数の型を調べてみると
print type(str)
実行結果
<type 'str'>
readメソッドの戻り値はバイト文字列であるstr型の値となっている。
str型に格納されてユニコード文字列をユニコードに変換して表示させるにはdecodeメソッドを使って
u_str=str.decode(encoding="utf-8") print type(u_str) print u_str
実行結果
<type 'unicode'> あいうえお かきくけこ abcd1234
decodeメソッドの部分についてはunicode関数を使って以下のように置き換える事もできる。
u_str=unicode(text_data, "utf-8")
今度は、ファイルの書き込みについてのサンプルを示そう。
u_str=u"""あいうえお かきくけこ abcd1234 """ f = open("uni_sample_out.txt",'w') b_str=u_str.encode("utf-8") f.write(b_str) f.close()
以下のサイトも参照。
codecsモジュールを利用する。 - python2でエンコードされたファイルを扱うためのopen関数
まわりくどい説明になったが、python2でエンコードされたファイルを標準のopen関数を使って読み込むのは面倒である。
このため、python2でエンコードされたファイルを読み込むには通常はcodecsモジュールに用意されている標準関数のopen関数とは別のopen関数を使うのが一般的なようだ。
import codecs f = codecs.open("uni_sample.txt",'r',encoding='utf-8') str=f.read() f.close() print str
codecsモジュールのopen関数はStreamReaderWriterクラスのインスタンスを返す。
StreamReaderWriterクラスには標準のoen関数が返すfileオブジェクトと同名のメソッドが用意されていてfileオブジェクトと同じように使えるようだ。
python3にもcodecsモジュールが使える。
ioモジュールを利用する。 - python2でpython3なみのopen関数を
codecsモジュールと同様にioモジュールにもopen関数が。
ioモジュールは「Python 3.x のために設計されたもの」なのだそうで、これがpython2.7でも使える。
import io f = io.open("uni_sample.txt",'r',encoding='utf-8') str=f.read() f.close() print str print f.__class__.__name__
実行結果
あいうえお かきくけこ abcd1234 TextIOWrapper
ioモジュールのopen関数はTextIOWrapperクラスのインスタンスを返すようだ。
open関数とファイルオブジェクト
これまでみてきたように、open関数には標準関数とcodecsモジュールの関数,ioモジュールの関数とがありどう使い分ければよいのか混乱してしまう。
ここで、これらのopen関数が返すファイルオブジェクトのクラスを整理してみよう。 (pythonではopen関数が返すオブジェクトの総称をファイルオブジェクトと呼んでいるみたい。)
open関数が返すオブジェクトのクラス
以下のコードを使って各open関数が返すオブジェクトのクラスを表示させてみると面白い結果になる。
python2の場合
import platform print platform.python_version() filename="sample.txt" print u"=========================== 標準のopen関数" f = open(filename,'r') print f.__class__.__name__ f.close() f = open(filename,'rb') print f.__class__.__name__ f.close() filename="sample.txt" f = open(filename,'w') print f.__class__.__name__ f.close() f = open(filename,'wb') print f.__class__.__name__ f.close() print u"=========================== codecsモジュールのopen関数" import codecs f = codecs.open(filename,'r') print f.__class__.__name__ f.close() f = codecs.open(filename,'rb') print f.__class__.__name__ f.close() f = codecs.open(filename,'w') print f.__class__.__name__ f.close() f = codecs.open(filename,'wb') print f.__class__.__name__ f.close() f = codecs.open(filename,'r',encoding='utf-8') print f.__class__.__name__ f.close() f = codecs.open(filename,'w',encoding='utf-8') print f.__class__.__name__ f.close() print u"=========================== ioモジュールのopen関数" import io f = io.open(filename,'r') print f.__class__.__name__ f.close() f = io.open(filename,'rb') print f.__class__.__name__ f.close() f = io.open(filename,'w') print f.__class__.__name__ f.close() f = io.open(filename,'wb') print f.__class__.__name__ f.close() f = io.open(filename,'r',encoding='utf-8') print f.__class__.__name__ f.close() f = io.open(filename,'w',encoding='utf-8') print f.__class__.__name__ f.close()
実行結果
2.7.8 =========================== 標準のopen関数 file file file file =========================== codecsモジュールのopen関数 file file file file StreamReaderWriter StreamReaderWriter =========================== ioモジュールのopen関数 TextIOWrapper BufferedReader TextIOWrapper BufferedWriter TextIOWrapper TextIOWrapper
python3の場合
import platform print(platform.python_version()) filename="sample.txt" print("=========================== 標準のopen関数") f = open(filename,'r') print(f.__class__.__name__) f.close() f = open(filename,'rb') print(f.__class__.__name__) f.close() filename="sample.txt" f = open(filename,'w') print(f.__class__.__name__) f.close() f = open(filename,'wb') print(f.__class__.__name__) f.close() print("=========================== codecsモジュールのopen関数") import codecs f = codecs.open(filename,'r') print(f.__class__.__name__) f.close() f = codecs.open(filename,'rb') print(f.__class__.__name__) f.close() f = codecs.open(filename,'w') print(f.__class__.__name__) f.close() f = codecs.open(filename,'wb') print(f.__class__.__name__) f.close() f = codecs.open(filename,'r',encoding='utf-8') print(f.__class__.__name__) f.close() f = codecs.open(filename,'w',encoding='utf-8') print(f.__class__.__name__) f.close() print("=========================== ioモジュールのopen関数") import io f = io.open(filename,'r') print(f.__class__.__name__) f.close() f = io.open(filename,'rb') print(f.__class__.__name__) f.close() f = io.open(filename,'w') print(f.__class__.__name__) f.close() f = io.open(filename,'wb') print(f.__class__.__name__) f.close() f = io.open(filename,'r',encoding='utf-8') print(f.__class__.__name__) f.close() f = io.open(filename,'w',encoding='utf-8') print(f.__class__.__name__) f.close()
実行結果
3.4.2 =========================== 標準のopen関数 TextIOWrapper BufferedReader TextIOWrapper BufferedWriter =========================== codecsモジュールのopen関数 TextIOWrapper BufferedReader TextIOWrapper BufferedWriter StreamReaderWriter StreamReaderWriter =========================== ioモジュールのopen関数 TextIOWrapper BufferedReader TextIOWrapper BufferedWriter TextIOWrapper TextIOWrapper
面倒臭いので、すべての場合について確認した訳では無いが、python2の場合は標準のopen関数とencoding引数を指定しないcodecsモジュールのopen関数はfileクラスのオブジェクトを,
encodingを指定したcodecsモジュールのopen関数はStreamReaderWriterクラスのオブジェクトを返すようだ。
そして、ioモジュールのopen関数はテキストモードでopenするとTextIOWrapperクラスのオブジェクトを、バイナリーモードでopenするとBufferedReader(読み込みモード)かBufferedWriter(書き込みモード)を返すようだ。
言い方を変えると、python2では標準のopen関数はfileクラスのオブジェクトを、python3の標準のopen関数はioモジュールのopen関数と同じオブジェクトを返す。
そしてcodecsモジュールのopen関数は、python2,python3ともにencodingを指定しない場合は標準のopen関数と同じクラスのファイルオブジェクトを、encodingを指定した場合はStreamReaderWriterクラスのオブジェクトを返すようだ。
曖昧な結論になるが、codecsモジュールはエンコーディングの処理に,io モジュールはストリーム処理に主点がおかれていて、
codecsモジュールのopen関数は、python2の標準のopen関数ではサポートされていなかったエンコーディングの処理もできるopen関数という位置づけだったのではないか。
そして、その後python3の標準のopen関数として新たに設計し直されたのがioモジュールのopen関数という事になる。
codecsモジュールとioモジュールは、python2とpython3の互換性のためにpython2とpython3のどちらでも使えるようになっているものと推察される。
どのopen関数を使いえば良いのだろうか?
では、これらの3つのopen関数をどう使い分ければ良いのかというと、私の個人的な見解としては、python2の場合はエンコーディングの処理が必要ない場合は標準のopen関数をエンコーディングが必要な場合には実績のあるcodecsモジュールのopen関数を。
そして曖昧な表現になるが、何らかの理由でpython3と同様の機能が必要な場合にはio モジュールのopen関数を使うという事になる。
python3の場合は標準のopen関数に新たに設計し直されたio モジュールのopen関数が組み込まれているので標準のopen関数だけで十分だろう。
もしpython2との互換性を重視する等何らかの理由がある場合はcodecsモジュールのopen関数を試してみるという事になるのでは。
ファイルオブジェクトの操作
重複するがこれまでのopen関数とファイルオブジェクトの公式ドキュメントのありかをまとめてみる。
python2とpython3とでファイルをオープンするには標準のopen関数とcodecsモジュールのopen関数,io モジュールのopen関数がある。
標準のopen関数
- 2. 組み込み関数 — Python 2.7.13 ドキュメント
open(name[, mode[, buffering]])
- 2. 組み込み関数 — Python 3.6.1 ドキュメント
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
codecsモジュールのopen関数
- 7.8. codecs — codec レジストリと基底クラス — Python 2.7.14rc1 ドキュメント
codecs.open(filename, mode[, encoding[, errors[, buffering]]])
- 7.2. codecs — codec レジストリと基底クラス — Python 3.6.2 ドキュメント
codecs.open(filename, mode='r', encoding=None, errors='strict', buffering=1)
ioモジュールの関数のopen関数
- 15.2. io — ストリームを扱うコアツール — Python 2.7.13 ドキュメント
io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)
python3のioモジュールの関数のopen関数は標準のopen関数と統合されている。
ファイルオブジェクトとは
あらためて、ファイルオブジェクトとは何なんだろうか?
-
file object (ファイルオブジェクト) 下位のリソースへのファイル志向 API (read() や write() メソッドを持つもの) を公開しているオブジェクトです。ファイルオブジェクトは、作成された手段によって、実際のディスク上のファイルや、その他のタイプのストレージや通信デバイス (例えば、標準入出力、インメモリバッファ、ソケット、パイプ、等) へのアクセスを媒介できます。ファイルオブジェクトは file-like objects や streams とも呼ばれます。 ファイルオブジェクトには3つの種類があります: 生のバイナリーファイル、バッファされたバイナリーファイル、そしてテキストファイルです。 これらのインターフェースは io モジュール内で定義されています。 ファイルオブジェクトを作成する標準的な方法は open() 関数を利用することです。
-
(ファイルオブジェクト) 下位のリソースへのファイル志向 API (read() や write() メソッドを持つもの) を公開しているオブジェクトです。ファイルオブジェクトは、作成された手段によって、実際のディスク上のファイルや、その他のタイプのストレージや通信デバイス (例えば、標準入出力、インメモリバッファ、ソケット、パイプ、等) へのアクセスを媒介できます。ファイルオブジェクトは file-like objects や streams とも呼ばれます。 ファイルオブジェクトには実際には 3 種類あります: 生の バイナリーファイル、バッファされた バイナリーファイル、そして テキストファイル です。インターフェイスは io モジュールで定義されています。ファイルオブジェクトを作る標準的な方法は open() 関数を使うことです。 file-like object file object と同義です。
それぞれのopen関数は異なるクラスのファイルオブジェクトを返すが、概ね同じファイルアクセスのメソッドを使ってファイルを操作できるようだ。
ファイルオブジェクトのクラス
あらためて、各ファイルオブジェクトのクラスのドキュメントへのリンクをピックアップ
fileクラス
python3ではfileクラスは廃止されているもよう。
StreamReaderWriterクラス
- 7.8. codecs — codec レジストリと基底クラス — Python 2.7.14rc1 ドキュメント
- 7.2. codecs — codec レジストリと基底クラス — Python 3.6.2 ドキュメント
TextIOWrapperクラス
BufferedReaderクラス
ファイル操作に関するサンプルコードと参考サイト
ファイル操作に関するサンプルコードもと思ったのだが、そろそろ調べるのも面倒になったので参考サイトのみをあげておく。
fileオブジェクトにはファイルの入出力をおこなうメソッドが用意されている。
- 7. 入力と出力 — Python 2.7.13 ドキュメント
- 【Python入門】ファイルの文字列の読み込みと書き込みの方法 | プロスタ
- Python: テキストファイルの読み込み – read()、readlines()、readline()メソッド
- ファイルアクセス - バリケンのPython日記 - pythonグループ
- Pythonでのファイル操作 - Qiita
テキストファイルの読み込みについては
readメソッド:全文読み込み
readlineメソッド:1行ずつ読み込み
readlines:すべての行をリスト形式で読み込み
テキストファイルの書き込みについては
writeメソッド:全文書き込み
writelineメソッド:1行ずつ書き込み
writelines:すべての行をリスト形式で書き込み
バイナリファイルのアクセス
バイナリファイルのアクセスのサンプルを
python2
# バイナリーデータのファイル出力 b_str_out=b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a' bin_file_name="sample.bin" f = open(bin_file_name,'wb') f.write(b_str_out) f.close() # バイナリーデータのファイル入力 f = open(bin_file_name,'rb') b_str_in=f.read() f.close() print(b_str_in.__class__.__name__) for c in b_str_in: print "{0:2x}".format(ord(c)), print
テキストファイルと同様、ファイルの書き込みにはwriteメソッド,読み込みにはreadメソッドが利用できる。
実行結果
str e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a
python3の場合、ファイルの書き込みのコードは同じなので読み込みのコードのみを示す。
python3
# バイナリーデータのファイル入力 f = open(bin_file_name,'rb') b_str_in=f.read() f.close() print(b_str_in.__class__.__name__) for i in b_str_in: print("{0:2x}".format(i),end=" ") print()
実行結果
bytes e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a
注目すべき点はreadメソッドの戻り値の型がpython2の場合はstr型なのに対してpython3の場合はbytes型になる点。
python2のstr型はバイト文字列なので当然といえばとうぜんなのだが。
また、ファイルアクセスとは関係ないが、for文の変数iやcに割り当てられる値の型がpython2の場合はバイト文字列なのに対して、python3の場合は数値型になる。
そして、print文にも違いが
参考URL
ファイルアクセスに付随する雑多な話題
python 標準入力 標準出力 パイプ
raw_input
- Python Tips:標準入力から文字列を取得したい - Life with Python
sys.stdin.readline のシリーズは、raw_input よりも広い用途で標準入力を取得するための関数群です。
sys ライブラリを import することで使えるようになります。
標準出力での文字コードの扱い
eofの判定
- ファイル - Dive Into Python 3 日本語版
少し意外かもしれないが、再びファイルの読み込みを行っても例外は発生しない。Pythonは、ファイルの終端 (EOF) からさらに読み込もうとしてもエラーとは見なさず、単に空の文字列を返すだけなのだ。
- pythonでEOFを明示的に取得する - Qiita
readline()の返り値が空文字のとき,EOFまで達しています.
...
ファイルオブジェクトからnext関数を呼び出した場合,EOFに達するとStopIterationという例外が発生します.これを捉えることで,EOFを検知できます.
with
- Pythonのwith構文の使い方 | UX MILK
with文を使うことによって、ファイルの閉め忘れやメモリの解放し忘れを防ぐことができ、例外処理にも強いより安全なプログラムを書くことができます。
with open("sample.txt", "r") as f: print f.read()
pythonにおけるwindowsのpathの区切り文字の扱い。
python path windows
デレクトリの区切り文字は\
なので文字列中に記述するには\\
と記述しなくてはならない。
芸がない記述は
path = "C:\\documents\\nori\\tama"
unix風にデレクトリの区切りに/
も使える。
path = "C:/documents/nori/tama"
でもどうしても\を使いたい場合は
path = r"C:\documents\nori\tama"
ただし末尾に'\'を付けるとエラーになる。
path = r"C:\documents\nori\tama\"
デレクトリとパスに対する操作
ファイルとディレクトリへのアクセス
ディレクトリとファイルの判別
ファイルの一覧を取得
ファイルのコピー
- 10.10. shutil — 高水準のファイル操作 — Python 2.7.14 ドキュメント
- ファイルシステム操作 - Python入門から応用までの学習サイト
- ファイルをコピーする - Python Tips
ファイル比較
- 10.5. filecmp — ファイルおよびディレクトリの比較 — Python 2.7.14 ドキュメント
- difflib – シーケンスを比較する - Python Module of the Week
- python filecmp ファイルの比較 : 忘れる前にメモ