数弱の文系大学生によるブログです。

Python、Webデザイン関連の記事を投稿していけたらなと思っています。

備忘録的なブログなので、読みにくい文章だと思います。ご了承ください。

Python3の復習(ファイル)

こんにちは。

かにたまごです。
数学復習の休憩にPythonの復習記事書いてます。
以前「復習しすぎwww」と友人に言われましたが、自分でも復習マニアかよって思いました(;^ω^)
Pythonの復習はともかく、数学に関しては復習に復習を重ねないと基礎が身につかないと思うので、復習マニアとしてもう少し頑張ります。


さて、今回は

  • ファイル

について、復習していきたいと思います。


今までのPython3 復習履歴は以下の通り。

  1. 数値・文字列
  2. リスト・タプル
  3. 辞書・集合
  4. if文・while文・for文
  5. 内包表記
  6. 関数
  7. ジェネレータ
  8. デコレータ
  9. 名前空間とスコープ
  10. アンダーバー・アンダースコアの意味
  11. エラー処理:try・except
  12. モジュール・パッケージ
  13. 標準ライブラリ
  14. オブジェクトとクラス①-クラスの定義-
  15. オブジェクトとクラス②-継承-
  16. プロパティ
  17. ポリモーフィズムとダックタイピング
  18. 特殊メソッドとその他諸々
  19. Unicodeとエンコード・デコード
  20. 書式指定
  21. 正規表現
  22. バイナリデータ

ファイル

  • ファイルを開く作業

ファイルを扱う場合、まずファイルを呼び出してから開く必要がある。
ファイルを呼び出し、開くには標準ライブラリの open() を使う。
第一引数にファイル名、第二引数に操作方法(mode)ファイルタイプを指定する。

操作方法の一覧

・ r = 読み出し
・ w = 書き込み(ファイルが存在しない場合は新規に作成される。存在する場合は上書き。
・ x = 新規ファイルに書き込み(ファイルが存在する場合はエラー。
・ a = ファイルに追記(ファイルが存在しない場合は、wと同様新規に作成される。)


ファイルタイプの一覧(操作方法の次に指定)

・ t(またはなし) = テキストデータ
・ b = バイナリデータ


この作業が終わった後にデータを読み書きする。

そして、最後に必ずファイルを閉じる必要がある。

  • ファイルへの書き込み(テキスト)

じゃあ実際に書き込みから試していこうと思う。

題材は、小説家になろうに投稿されていた『人間を倒すために、新人モンスターを募ったんだけど「100パーセント服にソースを飛ばせる」能力とか「お金をしまおうとするとき、床にばらまく」能力とかすげー地味で嫌な能力使いが募った件』(作者:黒豆パン)という小説。

タイトルに惹かれた・・・。


書き込みにはwrite()を使用する。

novel = """ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。"""

novel_size = len(novel)

print("文字数: ", novel_size)

fileobj = open("narou_novel", "wt")
size = fileobj.write(novel)

fileobj.close()

print("writeの戻り値: ", size)
文字数:  116
writeの戻り値:  116

print()で書き込むこともできる。

novel = """ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。"""

novel_size = len(novel)

print("文字数: ", novel_size)

fileobj = open("narou_novel", "wt")
print(novel, file=fileobj)

fileobj.close()
文字数:  116


書き込みデータが大きい場合は、チャンク(データの塊)に分けて少しずつ書き込んでいくと良い。

novel = """ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。"""

novel_size = len(novel)
offset = 0
chunk = 30

fileobj = open("narou_novel", "wt")

while True:
    if offset > novel_size:
        break
    size = fileobj.write(novel[offset:offset+chunk])
    print("{}字 書き込み".format(size))
    offset += chunk

fileobj.close()
30字 書き込み
30字 書き込み
30字 書き込み
26字 書き込み


上書きを避けたいような大切なファイルは xモードを使用すると例外を投げてくれるため良い。

novel = """ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。"""

novel_size = len(novel)
offset = 0
chunk = 30

fileobj = open("narou_novel", "xt")

while True:
    if offset > novel_size:
        break
    size = fileobj.write(novel[offset:offset+chunk])
    print("{}字 書き込み".format(size))
    offset += chunk

fileobj.close()
Traceback (most recent call last):
  File "C:\Users\***\Desktop\Python\Test\blog_test.py", line 1608, in <module>
    fileobj = open("narou_novel", "xt")
FileExistsError: [Errno 17] File exists: 'narou_novel'
  • ファイルの読み出し(テキスト)

ファイルの読み出しには、read()readline()readlines() を使用する。

read()・・・引数で字数に制限をかけることができる。引数を指定しない場合は、全てのデータを読み出す。

result = ""

novel_size = len(novel)
chunk = 30

fileobj = open("narou_novel", "rt")

while True:
    return_text = fileobj.read(chunk)
    if not return_text:
        break
    print("読み出したテキスト: {}\n文字数: {}字".format(return_text, len(return_text)))
    print("-"*100)
    result += return_text

fileobj.close()

print(result)
読み出したテキスト: ここは、とある男の城。ここでは今、モンスターの面接を行ってい
文字数: 30字
----------------------------------------------------------------------------------------------------
読み出したテキスト: る。

その城の主のイビラーは、新人モンスターを募集していた
文字数: 30字
----------------------------------------------------------------------------------------------------
読み出したテキスト: 。

それは、自分を討伐しに来る人間を返り討ちに合わせるとい
文字数: 30字
----------------------------------------------------------------------------------------------------
読み出したテキスト: うものであり、いうならばそれの戦力集めというやつだ。
文字数: 26字
----------------------------------------------------------------------------------------------------
ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。


readline()・・・ファイルを一行ずつ読み込む。

result = ""

fileobj = open("narou_novel", "rt")

while True:
    text_row = fileobj.readline()
    if not text_row:
        break
    print("読み出したテキスト: {}\n文字数: {}字".format(text_row, len(text_row)))
    print("-"*100)
    result += text_row

fileobj.close()

print(result)
読み出したテキスト: ここは、とある男の城。ここでは今、モンスターの面接を行っている。

文字数: 33字
----------------------------------------------------------------------------------------------------
#空白の行も一文字になる
読み出したテキスト: 

文字数: 1字
----------------------------------------------------------------------------------------------------
読み出したテキスト: その城の主のイビラーは、新人モンスターを募集していた。

文字数: 28字
----------------------------------------------------------------------------------------------------
読み出したテキスト: 

文字数: 1字
----------------------------------------------------------------------------------------------------
読み出したテキスト: それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。
文字数: 53字
----------------------------------------------------------------------------------------------------
ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。

readlines()・・・一度に一行ずつ読み出し、行数分の要素を持つリストを返す。

result = ""

fileobj = open("narou_novel", "rt")

text_rows = fileobj.readlines()

fileobj.close()

print("{}行のデータ".format(len(text_rows)))

for idx, row in enumerate(text_rows):
    print("{}行目のデータ: {}".format(idx+1, row))
5行のデータ

1行目のデータ: ここは、とある男の城。ここでは今、モンスターの面接を行っている。

2行目のデータ: 

3行目のデータ: その城の主のイビラーは、新人モンスターを募集していた。

4行目のデータ: 

5行目のデータ: それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。

イテレータを使って読み出すこともできる。

result = ""

fileobj = open("narou_novel", "rt")

for idx, row in enumerate(fileobj):
    print("{}行目のデータ: {}".format(idx+1, row))

fileobj.close()
1行目のデータ: ここは、とある男の城。ここでは今、モンスターの面接を行っている。

2行目のデータ: 

3行目のデータ: その城の主のイビラーは、新人モンスターを募集していた。

4行目のデータ: 

5行目のデータ: それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。
  • ファイルへの書き込み(バイナリ)

バイナリデータの書き込みを行う場合、操作方法(w、r...etc.)に続けて b を追加する。

byte_data = bytes(range(256))

fileobj = open("bfile", "wb")
fileobj.write(byte_data)
fileobj.close()
  • ファイルの読み込み(バイナリ)

読み込みも同様に、操作方法(w、r...etc.)に続けて b を追加する。

fileobj = open("bfile", "rb")
data = fileobj.read()

print(data)

fileobj.close()
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
  • ファイルを自動的にクローズする

今までは、fileobj.close() でファイルを閉じていたが、これだと閉め忘れる可能性がある。
そのような場合に備えて、自動的にファイルを閉じるwith構文を用いた方が良い。

result = ""
with open("narou_novel", "rt") as fileobj:
    result = fileobj.read()

print(result)
ここは、とある男の城。ここでは今、モンスターの面接を行っている。

その城の主のイビラーは、新人モンスターを募集していた。

それは、自分を討伐しに来る人間を返り討ちに合わせるというものであり、いうならばそれの戦力集めというやつだ。
  • tell()とseek()

ファイル先頭からのオフセットをバイト単位で返すtell()と別のオフセットに移動させるseek()

fileobj = open("bfile", "rb")
print(fileobj.tell())
last = fileobj.seek(255)
print(last)
0
255
  • 各種ファイル形式の取り扱い

よく使うであろうファイル形式の取り扱いについて、軽くメモしておく。

CSVファイル

import csv

language = [
    ["Python", "Guido van Rossum"],
    ["Ruby", "Yukihiro Matsumoto"],
    ["PHP", "Rasmus Lerdorf"],
    ["JavaScript", "Brendan Eich"],
    ["C#", "Anders Hejlsberg"],
]

with open("language", "wt") as fileobj:
    csvobj = csv.writer(fileobj)
    csvobj.writerows(language)


with open("language", "rt") as fileobj:
    csvobj = csv.reader(fileobj)
    result = [row for row in csvobj]

print(result)
[['Python', 'Guido van Rossum'], ['Ruby', 'Yukihiro Matsumoto'], ['PHP', 'Rasmus Lerdorf'], ['JavaScript', 'Brendan Eich'], ['C#', 'Anders Hejlsberg']]

DictReader() を使うと辞書のリストとして読み出せる。
その際、列名を指定することができる。

with open("language", "rt") as fileobj:
    csvobj = csv.DictReader(fileobj, fieldnames=["name", "developer"])
    result = [row for row in csvobj]
print(result)
[OrderedDict([('name', 'Python'), ('developer', 'Guido van Rossum')]), OrderedDict([('name', 'Ruby'), ('developer', 'Yukihiro Matsumoto')]), OrderedDict([('name', 'PHP'), ('developer', 'Rasmus Lerdorf')]), OrderedDict([('name', 'JavaScript'), ('developer', 'Brendan Eich')]), OrderedDict([('name', 'C#'), ('developer', 'Anders Hejlsberg')])]


JSONファイル

import json

languages = {
    "Ruby": {
        "developer": "Yukihiro Matsumoto",
        "year": 1993
    },
    "Python": {
        "developer": "Guido van Rossum",
        "year": 1990
    },
    "PHP": {
        "developer": "Rasmus Lerdorf",
        "year": 1995
    },
    "JavaScript": {
        "developer": "Brendan Eich",
        "year": 1995
    },
    "C#": {
        "developer": "Anders Hejlsberg",
        "year": 2000
    }
}

print(languages)
print(type(languages))

#ダンプすることでJSON文字列にエンコードされる
languages_json = json.dumps(languages)
print(languages_json)
print(type(languages_json))

#JSON文字列をPythonデータに変換する
languages_data = json.loads(languages_json)
print(languages_data)
print(type(languages_data))
{'Ruby': {'developer': 'Yukihiro Matsumoto', 'year': 1993}, 'Python': {'developer': 'Guido van Rossum', 'year': 1990}, 'PHP': {'developer': 'Rasmus Lerdorf', 'year': 1995}, 'JavaScript': {'developer': 'Brendan Eich', 'year': 1995}, 'C#': {'developer': 'Anders Hejlsberg', 'year': 2000}}
<class 'dict'>

{"Ruby": {"developer": "Yukihiro Matsumoto", "year": 1993}, "Python": {"developer": "Guido van Rossum", "year": 1990}, "PHP": {"developer": "Rasmus Lerdorf", "year": 1995}, "JavaScript": {"developer": "Brendan Eich", "year": 1995}, "C#": {"developer": "Anders Hejlsberg", "year": 2000}}
<class 'str'>

{'Ruby': {'developer': 'Yukihiro Matsumoto', 'year': 1993}, 'Python': {'developer': 'Guido van Rossum', 'year': 1990}, 'PHP': {'developer': 'Rasmus Lerdorf', 'year': 1995}, 'JavaScript': {'developer': 'Brendan Eich', 'year': 1995}, 'C#': {'developer': 'Anders Hejlsberg', 'year': 2000}}
<class 'dict'>


普段pandasの read_csv() ばっか使ってるから、新しいことだらけの復習時間だった(復習とは・・・)。


以上です。


参考にさせていただいたサイト:

人間を倒すために、新人モンスターを募ったんだけど「100パーセント服にソースを飛ばせる」能力とか「お金をしまおうとするとき、床にばらまく」能力とかすげー地味で嫌な能力使いが募った件