Pythonファイル入出力とバイナリ処理の実装

ファイルへの追記とデータ書き込み

ファイルを開く際、モード文字として'a'(append)を指定すると、ファイルの末尾にデータを追加する追記モードとして動作します。指定されたパスにファイルが存在しない場合、自動的に新規ファイルが作成されます。

# データの追記処理
with open('log_data.txt', 'a', encoding='utf-8') as file_obj:
    file_obj.write('処理開始\n')
    file_obj.write('システム稼働中\n')
    file_obj.write('処理完了\n')
# write()メソッドは文字列を書き込みます。改行が必要な場合は\nを明示的に含めます。

テキストモードとバイナリモードの違い

Pythonのファイル操作には、テキストを扱う「テキストモード(Text Mode)」と、画像や実行ファイルのようなバイト列を扱う「バイナリモード(Binary Mode)」が存在します。

テキストモード('t')はデフォルトの動作です(例: 'r', 'w'は内部的に'rt', 'wt'となります)。このモードでは、データは文字列(str型)として扱われ、encodingパラメータの指定が必須となります。

バイナリモード('b')は、任意のファイル形式を扱うためのモードです(例: 'rb', 'wb')。データはバイト列(bytes型)として扱われ、エンコーディングの指定は不要です。

# バイナリモードでの読み込みと書き込み
with open('source.bin', 'rb') as f:
    raw_data = f.read()
    # 読み込んだデータはbytes型となるため、そのまま表示するとエスケープシーケンスが見えます

# バイナリデータとして書き込む場合、文字列はencode()で変換する必要があります
with open('output.bin', 'wb') as f:
    text_content = "バイナリデータ"
    f.write(text_content.encode('utf-8'))

主要なファイル操作メソッド

  • .read(): ファイルの全内容を一度に読み込みます。
  • .readline(): ファイルから1行だけを読み込みます。
  • .readlines(): ファイルの全内容を読み込み、各行を要素とするリストを返します。
  • .readable(): ファイルが読み取り可能かどうかを判定します。
  • .write(str): 引数の文字列をファイルに書き込みます。
  • .writelines(list): リスト内の文字列要素をまとめて書き込みます。
  • .flush(): バッファに蓄積されたデータを即座にディスクに書き出します(強制保存)。

大容量ファイルの効率的な読み込み

.read()を使用して巨大なファイルを一度に読み込むと、メモリ不足(OOM)を引き起こすリスクがあります。また、一度読み込むとファイルポインタが末尾に移動するため、再度読み込むにはシーク(移動)操作が必要です。

これを解決する一般的なイディオムは、ファイルオブジェクトを直接イテレータとして使用し、行単位で処理することです。

# メモリ効率を考慮した行単位の読み込み
with open('large_dataset.log', 'r', encoding='utf-8') as file_stream:
    # forループでファイルオブジェクトを直接回すことで、1行ずつメモリに展開して処理します
    for line in file_stream:
        process(line)  # 各行に対する処理

実践:ファイルベースのユーザー認証システム

以下は、テキストファイルをデータベース代わりに使用した簡易的なユーザー登録およびログインシステムの実装例です。

import os

DB_FILE = 'user_database.txt'

# データベースファイルが存在しない場合は作成
if not os.path.exists(DB_FILE):
    with open(DB_FILE, 'w', encoding='utf-8') as f:
        pass

def main():
    while True:
        action = input("機能を選択してください [1:登録, 2:ログイン, その他:終了]: ").strip()
        
        if action == '1':
            # --- ユーザー登録 ---
            username = input("登録するユーザー名: ").strip()
            password = input("パスワード: ").strip()
            
            # ユーザー名の重複チェック
            is_duplicate = False
            with open(DB_FILE, 'r', encoding='utf-8') as f:
                for line in f:
                    stored_user, _ = line.strip().split('|')
                    if stored_user == username:
                        is_duplicate = True
                        print("エラー: このユーザー名は既に使用されています。")
                        break
            
            if not is_duplicate:
                # 重複がなければファイルに追加
                with open(DB_FILE, 'a', encoding='utf-8') as f:
                    # フォーマット: ユーザー名|パスワード
                    f.write(f"{username}|{password}\n")
                print(f"ユーザー '{username}' の登録が完了しました。")

        elif action == '2':
            # --- ユーザーログイン ---
            login_user = input("ユーザー名: ").strip()
            login_pass = input("パスワード: ").strip()
            
            authenticated = False
            with open(DB_FILE, 'r', encoding='utf-8') as f:
                for line in f:
                    # 改行文字を除去し、パイプで分割
                    parts = line.strip().split('|')
                    if len(parts) == 2:
                        stored_user, stored_pass = parts
                        if stored_user == login_user and stored_pass == login_pass:
                            authenticated = True
                            break
            
            if authenticated:
                print("ログイン成功!ようこそ。")
            else:
                print("ログイン失敗:ユーザー名またはパスワードが間違っています。")
        else:
            print("システムを終了します。")
            break

if __name__ == "__main__":
    main()

タグ: Python FileIO BinaryMode TextProcessing authentication

8月6日 07:24 投稿