Python講座 / withと文字コードを指定してテキストファイルを読み書きする

テキストファイルは文字コードを明示し、with文で処理後に閉じるようにします。wモードは既存内容を切り詰めるため、新しい出力を作る操作と、保存済みデータを置き換える操作を区別します。

モードと文字コードを選ぶ

モード 目的 既存ファイルとの関係
r 読み取り 存在しなければ失敗する
w 内容を置き換える書き込み 既存内容を切り詰める
a 追記 なければ作成する
x 新規作成のみ 存在すれば失敗する

文字コードはバイト列とテキストを対応付ける規則です。UTF-8のデータにはencoding="utf-8"を指定し、環境の既定値へ依存しないようにします。errors="ignore"は読み取れない内容を捨てることがあるため、文字化けを隠す一般的な解決策にはしません。

パスとファイルエラーの回復は、try・except・else・finally・raiseで例外を扱うで扱う規則とつながります。

書き込み・追記・読み取りを実行する

不要になってよい専用フォルダーでtext_files.pyを保存し、仮想環境でpython text_files.pyを実行します。実行のたびにnotes-demo.txtをwモードで初期化する例です。

from pathlib import Path

path = Path("notes-demo.txt")
with path.open("w", encoding="utf-8", newline="\n") as f:
    f.write("coffee:3500\n")
    f.write("lunch:8000\n")
with path.open("a", encoding="utf-8") as f:
    f.write("bus:2500\n")
with path.open("r", encoding="utf-8") as f:
    for line in f:
        print(line.rstrip("\n"))

予想結果です。

coffee:3500
lunch:8000
bus:2500

全体読み取りと行単位の処理を選ぶ

read()は残りの内容を文字列として返します。for line in fなら一行ずつ処理でき、必要がなければファイル全体をメモリーへ読み込まずに済みます。末尾まで読んだ後に再度読みたい場合は、開き直すか、意図して位置を移動します。

strip()は前後の空白も取り除くため、意味のある空白を失うことがあります。改行だけならrstrip("\n")のように対象を限定します。ファイルを開く際の改行設定によっても、改行文字が変換される場合があります。

原本を守り、ファイルの失敗を調べる

重要なデータは、別の一時ファイルへ書いて検証した後に、条件が整った場合だけ置き換える方法を検討します。withはファイルを閉じますが、書き込み前に切り詰めた元の内容を復元する機能ではありません。

FileNotFoundErrorではパスと親フォルダー、PermissionErrorでは権限やほかのアプリによるロックを調べます。UnicodeDecodeErrorでは実際の文字コードを特定し、バイトを捨てて済ませません。最初のwをaへ替えて二回目の重複を観察したら元へ戻します。pathlibで対象ファイルを特定してから、内容や文字コードを調べると切り分けやすくなります。

FileNotFoundErrorでは実際のパスと作業場所、UnicodeDecodeErrorでは実際の文字コード、PermissionErrorでは権限・ロック・ディレクトリーかどうかを確認します。すべての失敗を空文字列に変えると、ファイルがない場合と空の内容を区別できません。回復方針がある例外だけを処理します。

関連する公式リファレンス