40のおっさんのPython学習記録

20年以上前、学部の必修のC言語が全く理解できずに同級生に放り投げ、その後コーディングから遠ざかったガチ文系のおっさんが、ふと思い立ってPythonに挑戦しています。

新たな気づき(Chapter 13)

おっさんです。ヒノキの花粉症にやられており思考能力の低下が著しいです。おっさん、出張用のスマホAT&T iPhone 5をアンロックしたものを使い続けてきたんだけど、もう6年前の機種ということもあり、各種の動作が異様に遅くもう限界なので新しいスマホ買ったんです。BlackBerryのKeyONEというモデルのデュアルSIM機ですわ。日本で買うより安かったのでアメリカのAmazonで買うたわけですわ。

これが悲しいことに、SIMを指してもセルラーネットワークを安定して掴んでくれず、大半の時間は電波がありません状態なんですわ…アメリカのAmazonで買うてしもたせいで、返品がめんどくさそうでおっさん途方にくれています。どないしたらええねん…

ということで今日はファイル操作について学習しました。

  • open()は絶対/相対パスだけでなく、パスを読み込んだオブジェクトでも指定可能。
  • ファイルを開いたら、その開いた中身を使って処理をする前に.close()で閉じるのが鉄則。
  • 一方、with open() as構文を使うと、close()処理は必要ない。
file = "./fox.txt"
with open(file) as fileobj:
    text = fileobj.read()
    print(text)
  • コマンドライン引数を利用したい場合は、sysモジュールのargv属性の利用が必要なのでimport sysが必須。
  • コマンドライン引数とは、python code.py hoge hageの、hoge hageのみならず、code.pyも含む。
  • sys.argvにコマンドライン引数が渡される。上記の通りコードファイルが第1引数なのでargv[0]。hogeを利用したければargv[1]、hageを利用したければargv[2]で指定。
import sys
if len(sys.argv)<2: #1個目の引数はコードファイルなので、2個目にあるはずのパス名がない場合の処理
    print("読み込むファイル名を指定して下さい。")
    sys.exit()

file = sys.argv[1]  #[0]はコードファイルなので、[1]でパス名を取る
with open(file) as fileobj:
    text = fileobj.read()
    print(text)
  • read(x)とすると、x文字読む。もう一度同じオブジェクトにread(x)するとその次のx文字を読み込む。
file = "./fox.txt"
with open(file) as fileobj:
    while True:
        text = fileobj.read(10)  #10文字ずつ読むことを繰り返す
        if text:                 #文字列があれば出力
            print(text)
        else:                    #文字列がなくなったら終了
            break
  • readline()は1行ずつ読み込むことのできるメソッド。1行終わると次の行に進む。
file = "./rihaku_kanshi.txt"
with open(file) as fileobj:
    while True:
        line = fileobj.readline() #1行ずつ読み込む
        aline = line.rstrip()     #読み込んだ行の最後にある改行を削除
        if aline:
            print(aline)
        else:
            break
  • 上記を李白漢詩を読み込んだら以下の通りになる。改行コードを削除しないと行間に更にもう1行含まれる間延びした出力になるので要注意。
花間一壼酒  花間一壺の酒
獨酌無相親  独り酌んで相親しむもの無し
舉杯邀明月  杯を挙げて明月を迎え
對影成三人  影に対して三人と成る
月既不解飮  月既に飲を解せず
影徒隨我身  影徒らに我が身に随う
暫伴月將影  暫く月と影とを伴い
行樂須及春  行楽須らく春に及ぶべし
我歌月徘徊  我歌えば月徘徊し
我舞影零亂  我舞えば影零乱す
醒時同交歡  醒むる時は同に交歡し
醉後各分散  酔うて後は各分散す
永結無情遊  永く無情の遊を結び
相期遥雲漢  相期す遥かなる雲漢に
  • open()で読み込んだオブジェクトそのものが行単位で要素を取り出せるイテレータなので、next(fileobj)で1行ずつ取り出せる。以下のコードで同じことができる。
file = "./rihaku_kanshi.txt"
with open(file) as fileobj:
    while True:
        try:
            line = next(fileobj)
            aline = line.rstrip()
            print(aline)
        except StopIteration:
            break
  • for-in enumerateを使うと次のように書ける
file = "./rihaku_kanshi.txt"

with open(file) as fileobj:
    for i, line in enumerate(fileobj,1): #iの開始番号を0でなく1にするために,1を付加
        if line == "\n":
            continue
        aline = line.rstrip()
        print(f"{i}:{aline}")

出力結果は以下のような感じ。

1:花間一壼酒  花間一壺の酒
2:獨酌無相親  独り酌んで相親しむもの無し
3:舉杯邀明月  杯を挙げて明月を迎え
4:對影成三人  影に対して三人と成る
5:月既不解飮  月既に飲を解せず
6:影徒隨我身  影徒らに我が身に随う
7:暫伴月將影  暫く月と影とを伴い
8:行樂須及春  行楽須らく春に及ぶべし
9:我歌月徘徊  我歌えば月徘徊し
10:我舞影零亂  我舞えば影零乱す
11:醒時同交歡  醒むる時は同に交歡し
12:醉後各分散  酔うて後は各分散す
13:永結無情遊  永く無情の遊を結び
14:相期遥雲漢  相期す遥かなる雲漢に
  • ファイルに書き込む場合はopen()メソッドに"w"あるいは"a"のモードオプションをつける。"w"は既存の内容を消して上書き、"a"は追記。
  • with-asを使えばclose()しなくていいのは書き込みも同じ。
  • 以下の事例はpython code.py 文字列を実行すると、実行時間、書き込み文字列を区切り線とともにどんどんファイルに追記していく。
import sys
from datetime import datetime
file = "./log.txt"

#文字列の引数がない場合は処理を中断
if len(sys.argv)<2:
    sys.exit()

now  = str(datetime.now())
memo = sys.argv[1] #文字列の引数
line = "-"*10 #区切り線
with open(file, "a") as fileobj:
    fileobj.write(now+"\n")  #書き込み時間を入れる
    fileobj.write(memo+"\n") #引数を入れる
    fileobj.write(line+"\n") #区切り線を入れる
  • 書き込みの場合のダイアログを呼び出す場合はtkinterのasksaveasfilenameメソッドを呼び出す。
  • ファイルはなければ作成されるが、フォルダの場合はない場合は作成されずエラーになる。なので事前にフォルダの有無を確認する必要が出て来る。os.path.exists(パス)でファイル、フォルダが存在するかどうかが確認できる。Trueで存在、Falseで非存在。逆にファイルはある場合は上書きされることにもなりかねないので、os.path.exists(パス/ファイル名)でファイルの有無を調べ、注意をうながすこともありえる。
import os
from random import randint

#保存フォルダとパス
folder = "./data/"
file = folder+"sample.txt"

#ファイルを保存する
def filewrite():
    if not os.path.exists(folder): #フォルダの存在を確認
        os.makedirs(folder)        #なければフォルダを作成
    with open(file, "w") as fileobj: #ファイルはあれば既存のものが開き、なければ新規に作成される
        num = randint(0,100)
        fileobj.write(f"{num}が出ました。")
        print("ファイルを保存しました。")

#既存のファイルの有無をチェック。あれば注意をうながすメッセージを表示。
if os.path.exists(file):
    while True:
        answer = input("上書きしてもよいですか? (y/n)")
        if answer == "y":
            filewrite()
            break
        elif answer == "n":
            break
else:
    filewrite()