Python入門:ファイル操作(読み書き)

2025-10-24

はじめに

今回は、プログラムの実行結果を永続化したり、外部データを読み込んだりするために不可欠な「ファイル操作」について学びます。ファイル操作をマスターすることで、データの保存・読み込みが可能になり、より実用的なプログラムを作成できるようになります。

ファイル操作の重要性

ファイル操作は、プログラムと外部世界をつなぐ重要な役割を持っています。プログラムはメモリ上だけで動作していると、終了した瞬間にデータが失われてしまいます。しかし、ファイルを利用することで、設定情報や処理結果を長期間保存できるようになります。

たとえば、設定ファイルの読み書きを行うことで、アプリケーションの動作内容を保存し、次回起動時にも同じ設定を利用できます。また、データをファイルとして保存することで、プログラム終了後も情報を保持できるため、永続的なデータ管理が可能になります。

さらに、ログファイルを作成することで、エラーや実行履歴を記録できるため、問題調査や運用管理に役立ちます。外部データのインポートやエクスポートでは、CSVやJSONなどのファイルを通じて、他のシステムとデータをやり取りできます。

加えて、大規模データの処理でもファイル操作は重要です。大量のデータを一度にメモリへ読み込むのではなく、必要な部分だけを順番に処理することで、効率的にデータを扱えるようになります。

ファイル操作の基本

ファイルのオープンとクローズ

Pythonでファイルを操作する基本的な流れは「オープン → 操作 → クローズ」です。

open() でファイルを開き、read() で内容を読み込み、最後に close() でファイルを閉じています。
try-finally 構文を使うことで、処理中にエラーが発生しても必ず file.close() が実行され、
リソースリーク(ファイルを閉じ忘れる問題)を防ぐ安全な構成になっています。

# 基本的なファイル操作
try:
    # ファイルをオープン(読み込みモード)
    file = open('sample.txt', 'r', encoding='utf-8')

    # ファイルの操作
    content = file.read()
    print(content)

finally:
    # ファイルをクローズ
    file.close()

try-finallyとは

try-finally は、「途中でエラーが起きても、最後に必ず実行したい処理」を書くための構文です。

例えば次のコードです。

print("処理開始")

try:
    num = 10 / 0
    print(num)

finally:
    print("最後に必ず実行されます")

このコードでは 10 / 0 でエラーが発生します。

しかし、finally の中の処理は必ず実行されるため、処理最後に必ず実行されます。つまり finally は、「エラーがあっても必ず動く終了処理」を書く場所です。ファイル操作では、途中でエラーが起きてもファイルを閉じる必要があるため try を使います。

with文を使った安全なファイル操作

with文を使用すると、ファイルのクローズを自動で行ってくれます。with open(...) as file: と書くことで、ブロック内の処理が終わると自動的にファイルが閉じられます。

これにより、close() を明示的に書く必要がなく、エラーが起きても安全にリソースを解放できます。
可読性が高く、推奨されるファイル操作の方法です。

# with文を使った安全なファイル操作
with open('sample.txt', 'r', encoding='utf-8') as file:
    content = file.read()
    print(content)
# ここで自動的にファイルがクローズされる

ファイルの読み込み

さまざまな読み込み方法

sample.txtを作成し、read()で全体を一括取得、readline()で1行ずつ、readlines()で行リストとして取得、さらにファイルオブジェクトを直接反復処理し、最後に指定バイト数のみを読み込む手法を順に実演しています。

def demonstrate_reading():
    """さまざまなファイル読み込み方法を演示"""

    # サンプルファイルを作成
    sample_content = """これは1行目です。
これは2行目です。
これは3行目です。
4行目には数字123が含まれています。
5行目は最後の行です。"""

    with open('sample.txt', 'w', encoding='utf-8') as f:
        f.write(sample_content)

    print("=== ファイル読み込みのデモ ===")

    # 1. read() - ファイル全体を一括読み込み
    with open('sample.txt', 'r', encoding='utf-8') as f:
        content = f.read()
        print("1. read() メソッド:")
        print(content)
        print("-" * 40)

    # 2. readline() - 1行ずつ読み込み
    with open('sample.txt', 'r', encoding='utf-8') as f:
        print("2. readline() メソッド:")
        line1 = f.readline()
        line2 = f.readline()
        print(f"1行目: {line1.strip()}")
        print(f"2行目: {line2.strip()}")
        print("-" * 40)

    # 3. readlines() - すべての行をリストで読み込み
    with open('sample.txt', 'r', encoding='utf-8') as f:
        lines = f.readlines()
        print("3. readlines() メソッド:")
        for i, line in enumerate(lines, 1):
            print(f"行{i}: {line.strip()}")
        print("-" * 40)

    # 4. ファイルオブジェクトを直接イテレート
    with open('sample.txt', 'r', encoding='utf-8') as f:
        print("4. ファイルオブジェクトのイテレーション:")
        for i, line in enumerate(f, 1):
            print(f"行{i}: {line.strip()}")
        print("-" * 40)

    # 5. 特定のバイト数だけ読み込み
    with open('sample.txt', 'r', encoding='utf-8') as f:
        print("5. 特定バイト数の読み込み:")
        first_10_bytes = f.read(10)
        print(f"最初の10バイト: {first_10_bytes}")
        print("-" * 40)

# デモの実行
demonstrate_reading()

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

open()を使ってファイルを1行ずつ読み込み、行数・単語数・文字数をカウントします。1000行ごとに進捗を表示し、最後に統計結果を出力します。メモリを無駄に使わず、大規模データ処理に適した構成です。

def process_large_file(filename):
    """大きなファイルをメモリ効率的に処理する"""
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            line_count = 0
            word_count = 0
            char_count = 0

            for line in file:
                line_count += 1
                word_count += len(line.split())
                char_count += len(line)

                # 1000行ごとに進捗を表示
                if line_count % 1000 == 0:
                    print(f"処理中... {line_count}行")

            print(f"ファイル統計:")
            print(f"  行数: {line_count}")
            print(f"  単語数: {word_count}")
            print(f"  文字数: {char_count}")

    except FileNotFoundError:
        print(f"ファイル '{filename}' が見つかりません")
    except IOError as e:
        print(f"ファイル読み込みエラー: {e}")

# 使用例
# process_large_file('large_data.txt')

ファイルの書き込み

さまざまな書き込み方法

write()で単一文字列を、writelines()で複数行リストを出力し、aモードで追記操作も紹介します。さらにディクショナリデータをCSV形式に整形して書き込み、最後に作成した各ファイルを読み出して内容を確認します。ファイル出力の基本と実用例を総合的に学べる構成です。

def demonstrate_writing():
    """さまざまなファイル書き込み方法を演示"""

    print("=== ファイル書き込みのデモ ===")

    # 1. write() - 文字列を書き込み
    with open('output1.txt', 'w', encoding='utf-8') as f:
        f.write("これはwrite()メソッドで書き込まれたテキストです。\n")
        f.write("2行目を追加します。\n")
        print("1. write()メソッドでファイルを作成しました")

    # 2. writelines() - 文字列のリストを書き込み
    lines = [
        "これはwritelines()で書き込まれたテキストです。\n",
        "リストの各要素が1行になります。\n",
        "最後の行です。\n"
    ]

    with open('output2.txt', 'w', encoding='utf-8') as f:
        f.writelines(lines)
        print("2. writelines()メソッドでファイルを作成しました")

    # 3. 追記モードでの書き込み
    with open('output3.txt', 'w', encoding='utf-8') as f:
        f.write("最初の内容\n")

    with open('output3.txt', 'a', encoding='utf-8') as f:  # 'a'は追記モード
        f.write("追記された内容\n")
        f.write("さらに追記\n")
        print("3. 追記モードでファイルを更新しました")

    # 4. フォーマット済み文字列の書き込み
    students = [
        {"name": "山田太郎", "score": 85},
        {"name": "佐藤花子", "score": 92},
        {"name": "鈴木一郎", "score": 78}
    ]

    with open('students.txt', 'w', encoding='utf-8') as f:
        f.write("名前,点数\n")  # ヘッダー行
        for student in students:
            line = f"{student['name']},{student['score']}\n"
            f.write(line)
        print("4. CSV形式でデータを書き込みました")

    # 作成されたファイルの内容を確認
    print("\n作成されたファイルの内容:")
    for filename in ['output1.txt', 'output2.txt', 'output3.txt', 'students.txt']:
        print(f"\n{filename}:")
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                print(f.read())
        except FileNotFoundError:
            print("ファイルが見つかりません")

# デモの実行
demonstrate_writing()

ファイルモードの詳細

主要なファイルモード

open()関数の第2引数で指定し、ファイル操作の目的を決定します。主なものに、読み込み専用の'r'、書き込み専用(既存内容を上書き)の'w'、追記用の'a'、読み書き両用の'r+'、新規作成専用の'x'があります。また、バイナリ操作では'rb''wb'のようにbを付けて使用します。

モード説明ファイルが存在する場合ファイルが存在しない場合
'r'読み込み(デフォルト)読み込み可エラー
'w'書き込み上書き新規作成
'a'追記末尾に追加新規作成
'r+'読み込み+書き込み読み書き可エラー
'w+'書き込み+読み込み上書き新規作成
'a+'追記+読み込み読み込みと追記新規作成
'x'排他的作成エラー新規作成

バイナリモード

テキストをUTF-8でエンコードしてバイナリ形式で保存し、再度デコードして読み出す処理を示します。

バイナリ(Binary)**とは、コンピュータが扱う「0」と「1」の2進数を基にしたデータ表現方式です。バイナリという用語は、英語の「binary(双対)」に由来し、コンピュータ内部でデータや命令を表現する際に、0と1の組み合わせを使って情報を扱います。

def binary_file_operations():
    """バイナリファイルの操作"""

    # テキストデータをバイナリで書き込み
    text_data = "これはバイナリで保存されるテキストです"

    with open('binary_text.bin', 'wb') as f:  # 'wb' = バイナリ書き込みモード
        f.write(text_data.encode('utf-8'))
        print("テキストをバイナリファイルとして保存しました")

    # バイナリファイルの読み込み
    with open('binary_text.bin', 'rb') as f:  # 'rb' = バイナリ読み込みモード
        binary_content = f.read()
        text_content = binary_content.decode('utf-8')
        print(f"バイナリファイルから読み込んだテキスト: {text_content}")

    # バイトデータの操作
    byte_data = bytes([65, 66, 67, 68, 69])  # ABCDE

    with open('bytes_data.bin', 'wb') as f:
        f.write(byte_data)
        print("バイトデータをファイルに保存しました")

    with open('bytes_data.bin', 'rb') as f:
        read_bytes = f.read()
        print(f"読み込んだバイトデータ: {list(read_bytes)}")
        print(f"文字列として: {read_bytes.decode('ascii')}")

# バイナリ操作のデモ
binary_file_operations()

さらに、bytes()で作成したバイト配列(例:A〜E)をファイルに保存し、読み込んでバイト列および文字列として表示します。バイナリ入出力の基本理解に役立つ構成です。

Pythonのファイル操作ベストプラクティス

CSVファイルの操作

csvモジュールを使ってCSVファイルを読み書きする方法を実演しています。

CSVファイル(.csv)とは、表計算ソフトなどのデータを「カンマ(,)」で区切って並べたシンプルなテキストファイルです。文字データのみで構成されるためファイルサイズが非常に軽く、Excelだけでなく、メモ帳や異なるシステム間でのデータ共有や引っ越しに広く活用されています。

import csv

def csv_operations():
    """CSVファイルの読み書き"""

    # CSVファイルの書き込み
    students = [
        ['名前', '年齢', '点数', 'クラス'],
        ['山田太郎', 18, 85, 'A'],
        ['佐藤花子', 17, 92, 'B'],
        ['鈴木一郎', 18, 78, 'A'],
        ['田中美咲', 17, 88, 'B']
    ]

    # CSVモジュールを使用した書き込み
    with open('students.csv', 'w', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        writer.writerows(students)
        print("CSVファイルを作成しました")

    # CSVファイルの読み込み
    print("\nCSVファイルの内容:")
    with open('students.csv', 'r', encoding='utf-8') as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)

    # ディクショナリ形式でのCSV操作
    print("\nディクショナリ形式でのCSV操作:")
    with open('students.csv', 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for row in reader:
            print(f"名前: {row['名前']}, 年齢: {row['年齢']}, 点数: {row['点数']}")

# CSV操作のデモ
csv_operations()

writer.writerows()で学生データを表形式に書き込み、次にcsv.reader()でリスト形式として読み出します。さらにcsv.DictReader()を用いてディクショナリ形式で各行のデータを扱い、キー名で値を取得します。CSV操作の基本を網羅した実践的な例です。

設定ファイルの管理

jsonモジュールを用いて設定ファイルを操作する例です。

jsonモジュールとは、軽量なデータ形式であるJSONをプログラム上で処理するための機能(関数やクラス)がまとめられたライブラリです。JSON(データ形式)はディクショナリ形式と似ており「キーと値をペアで管理する」という共通点があります。

import json

def config_file_operations():
    """JSON設定ファイルの操作"""

    # 設定データ
    config_data = {
        "app_name": "My Application",
        "version": "1.0.0",
        "settings": {
            "theme": "dark",
            "language": "ja",
            "auto_save": True
        },
        "recent_files": [
            "document1.txt",
            "document2.txt"
        ]
    }

    # JSONファイルへの書き込み
    with open('config.json', 'w', encoding='utf-8') as f:
        json.dump(config_data, f, ensure_ascii=False, indent=2)
        print("設定ファイルを保存しました")

    # JSONファイルからの読み込み
    with open('config.json', 'r', encoding='utf-8') as f:
        loaded_config = json.load(f)
        print("設定ファイルを読み込みました:")
        print(json.dumps(loaded_config, ensure_ascii=False, indent=2))

    # 設定の更新
    loaded_config['settings']['theme'] = 'light'
    loaded_config['recent_files'].append('document3.txt')

    with open('config_updated.json', 'w', encoding='utf-8') as f:
        json.dump(loaded_config, f, ensure_ascii=False, indent=2)
        print("更新された設定ファイルを保存しました")

# 設定ファイル操作のデモ
config_file_operations()

ディクショナリ形式の設定データをjson.dump()で整形してconfig.jsonに保存し、json.load()で読み込み内容を確認します。その後、テーマ設定を変更し、最近のファイルに新しい項目を追加して更新版を再保存します。設定管理やアプリ構成ファイルの扱いに役立つ実践的なサンプルです。

ログファイルの作成

write_log()関数で現在時刻とログレベル(INFOやERRORなど)を付与してapp.logに追記し、同時にコンソールにも出力します。起動、ログイン、エラー、完了といったイベントを記録し、最後にログファイル全体を読み込んで表示します。実用的な基本構造を持つログ処理の入門例です。

import datetime

def create_log_system():
    """シンプルなログシステム"""

    def write_log(message, level="INFO"):
        """ログをファイルに書き込む"""
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] [{level}] {message}\n"

        with open('app.log', 'a', encoding='utf-8') as f:
            f.write(log_entry)

        print(log_entry.strip())  # コンソールにも表示

    # ログの使用例
    write_log("アプリケーションを起動しました")
    write_log("ユーザーログイン: alice", "INFO")
    write_log("データベース接続エラー", "ERROR")
    write_log("処理が完了しました", "INFO")

    # ログファイルの内容を表示
    print("\nログファイルの内容:")
    try:
        with open('app.log', 'r', encoding='utf-8') as f:
            print(f.read())
    except FileNotFoundError:
        print("ログファイルが見つかりません")

# ログシステムのデモ
create_log_system()

osモジュールを使った操作

osshutilモジュールを使い、現在の作業ディレクトリ取得、ファイル存在確認、ディレクトリ作成、ファイルコピー・リネーム・削除、一覧取得、ディレクトリ削除といった一連の処理を行います。実際のファイル管理やバックアップ処理の基礎を学ぶのに最適な例です。

import os
import shutil

def file_system_operations():
    """ファイルシステムの操作"""

    print("=== ファイルシステム操作 ===")

    # カレントディレクトリの取得
    current_dir = os.getcwd()
    print(f"現在のディレクトリ: {current_dir}")

    # ファイルの存在確認
    files_to_check = ['sample.txt', 'nonexistent.txt', 'students.csv']
    for filename in files_to_check:
        exists = os.path.exists(filename)
        print(f"ファイル '{filename}' の存在: {exists}")

    # ディレクトリの作成
    if not os.path.exists('test_dir'):
        os.makedirs('test_dir')
        print("ディレクトリ 'test_dir' を作成しました")

    # ファイルのコピー
    if os.path.exists('sample.txt'):
        shutil.copy('sample.txt', 'test_dir/copied_sample.txt')
        print("ファイルをコピーしました")

    # ファイルのリネーム
    if os.path.exists('test_dir/copied_sample.txt'):
        os.rename('test_dir/copied_sample.txt', 'test_dir/renamed_sample.txt')
        print("ファイルをリネームしました")

    # ディレクトリ内のファイル一覧
    print("\nディレクトリ内のファイル:")
    for item in os.listdir('.'):
        if os.path.isfile(item):
            item_type = "ファイル"
        elif os.path.isdir(item):
            item_type = "ディレクトリ"
        else:
            item_type = "その他"

        size = os.path.getsize(item)
        print(f"  {item} ({item_type}, {size} バイト)")

    # ファイルの削除
    if os.path.exists('test_dir/renamed_sample.txt'):
        os.remove('test_dir/renamed_sample.txt')
        print("ファイルを削除しました")

    # ディレクトリの削除
    if os.path.exists('test_dir'):
        os.rmdir('test_dir')
        print("ディレクトリを削除しました")

# ファイルシステム操作のデモ
file_system_operations()

堅牢なファイル操作

例外処理を活用して安全にファイルを読み書きする方法を示しています。safe_read_file()はファイルの存在・権限・文字コード・入出力エラーを個別に捕捉し、問題発生時に詳細なエラーメッセージを表示します。safe_write_file()も同様に権限やI/Oエラーを検知し、安全に書き込みを行います。堅牢で信頼性の高いファイル操作を行うための実践的サンプルです。

def robust_file_operations():
    """エラーハンドリングを含む堅牢なファイル操作"""

    def safe_read_file(filename):
        """安全なファイル読み込み"""
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            print(f"エラー: ファイル '{filename}' が見つかりません")
            return None
        except PermissionError:
            print(f"エラー: ファイル '{filename}' の読み込み権限がありません")
            return None
        except UnicodeDecodeError:
            print(f"エラー: ファイル '{filename}' の文字コードが正しくありません")
            return None
        except IOError as e:
            print(f"エラー: ファイル操作中に問題が発生しました - {e}")
            return None

    def safe_write_file(filename, content):
        """安全なファイル書き込み"""
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(content)
            print(f"ファイル '{filename}' への書き込みが成功しました")
            return True
        except PermissionError:
            print(f"エラー: ファイル '{filename}' への書き込み権限がありません")
            return False
        except IOError as e:
            print(f"エラー: ファイル書き込み中に問題が発生しました - {e}")
            return False

    # 安全なファイル操作の使用例
    content = safe_read_file('sample.txt')
    if content:
        print("ファイルの内容:")
        print(content)

    # 新しい内容の書き込み
    new_content = "これは安全なファイル操作で書き込まれた内容です"
    success = safe_write_file('safe_output.txt', new_content)

    if success:
        # 書き込んだ内容を確認
        verified_content = safe_read_file('safe_output.txt')
        if verified_content:
            print("書き込まれた内容を確認:")
            print(verified_content)

# 堅牢なファイル操作のデモ
robust_file_operations()

大きなファイルの処理

大容量ファイルを効率よく処理するための実践例です。process_large_file_in_chunks()では一定サイズ(チャンク)ごとに読み込み、逐次的に行を処理してメモリ使用量を抑えます。memory_efficient_search()はファイルを1行ずつ走査して特定語句を検索し、ヒットした行番号と内容を記録します。大量データ処理やログ解析などに有効な、メモリ効率を重視した設計です。

def efficient_large_file_processing():
    """大きなファイルを効率的に処理する"""

    def process_large_file_in_chunks(filename, chunk_size=8192):
        """チャンク単位で大きなファイルを処理する"""
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                buffer = ""
                chunk_count = 0
                line_count = 0

                while True:
                    chunk = f.read(chunk_size)
                    if not chunk:
                        break

                    chunk_count += 1
                    buffer += chunk

                    # バッファから行を処理
                    while '\n' in buffer:
                        line, buffer = buffer.split('\n', 1)
                        line_count += 1

                        # 行の処理(ここでは単純にカウント)
                        if line_count % 1000 == 0:
                            print(f"処理済み: {line_count}行")

                # 最後のバッファ内容を処理
                if buffer:
                    line_count += 1

                print(f"処理完了: {line_count}行, {chunk_count}チャンク")

        except FileNotFoundError:
            print(f"ファイル '{filename}' が見つかりません")

    def memory_efficient_search(filename, search_term):
        """メモリ効率的なファイル検索"""
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                matches = []
                line_number = 0

                for line in f:
                    line_number += 1
                    if search_term in line:
                        matches.append((line_number, line.strip()))

                return matches

        except FileNotFoundError:
            print(f"ファイル '{filename}' が見つかりません")
            return []

    # 大きなファイルを作成(デモ用)
    with open('large_demo.txt', 'w', encoding='utf-8') as f:
        for i in range(10000):
            f.write(f"これは行 {i+1} です。サンプルテキストが含まれています。\n")

    print("大きなファイルを処理中...")
    process_large_file_in_chunks('large_demo.txt')

    print("\nファイル内の検索:")
    results = memory_efficient_search('large_demo.txt', 'サンプル')
    print(f"検索結果: {len(results)}件見つかりました")
    if results:
        print("最初の5件:")
        for line_num, line in results[:5]:
            print(f"  行{line_num}: {line}")

# 効率的なファイル処理のデモ
efficient_large_file_processing()

まとめ

Pythonのファイルの開閉や操作の基本的な流れを理解し、with 文を用いた安全で自動的にクローズされるファイル操作方法を習得しました。さらに、read()readline()readlines() を使った読み込み、write()writelines() による書き込み、追記モードなどの使い分けも学びました。

また、CSV・JSON・ログなどの実践的なファイル処理や、ファイルやディレクトリを扱うファイルシステム操作、例外処理による堅牢な設計、そして大規模ファイルを効率的に扱うためのパフォーマンス最適化についても理解を深めました。

ファイル操作は、データの永続化や外部システムとの連携に不可欠なスキルです。適切なエラーハンドリングと効率的な処理方法を理解することで、より信頼性の高いプログラムを作成できるようになります。


演習問題

初級問題(3問)

問題1

「study.txt」という名前のテキストファイルを作成し、次の内容を書き込みます。

1行目: Pythonの学習
2行目: ファイル操作の練習
3行目: 読み書きの基本

問題2

問題1で作成した「study.txt」のテキストファイルにさらに以下の4行を追加してください。

4行目: open関数の使い方
5行目: writeメソッドの練習
6行目: テキストファイルの保存
7行目: プログラミングは楽しい

その後、ファイルの内容をすべて表示します。

実行結果:

1行目: Pythonの学習
2行目: ファイル操作の練習
3行目: 読み書きの基本
4行目: open関数の使い方
5行目: writeメソッドの練習
6行目: テキストファイルの保存
7行目: プログラミングは楽しい

問題3

問題2で作成した「study.txt」を読み込んで行数をカウントして表示してください。

中級問題(6問)

問題4
CSVファイルをプログラムで生成し、以下の学生データを書き込むプログラムを作成してください。

名前,科目,点数
山田太郎,数学,85
佐藤花子,英語,92
鈴木一郎,科学,78

その後、このCSVファイルを読み込んで各学生のデータを表示してください。

students.csv を作成しました

名前,科目,点数
山田太郎,数学,85
佐藤花子,英語,92
鈴木一郎,科学,78

問題5
「student_config.json」というJSONファイルを作成し、次の学生情報を保存するプログラムを作成してください。

学校名: Python高校
クラス: 3年A組
担任: 田中先生
生徒一覧
山田太郎: 数学 85点
佐藤花子: 英語 92点
鈴木一郎: 理科 78点

作成したJSONファイルを再度読み込み、画面へ表示してください。

JSONファイルを保存しました

学校名: Python高校
クラス: 3年A組

担任: 田中先生

生徒一覧
--------------------

名前: 山田太郎
科目: 数学
点数: 85

--------------------

名前: 佐藤花子
科目: 英語
点数: 92

--------------------

名前: 鈴木一郎
科目: 理科
点数: 78

問題6

「study_log.txt」というログファイルを作成し、学習記録を保存するプログラムを作成してください。実行イメージの通りのログを記録します。ログの形式は次のようにする

[2026-05-15 10:30:00] Pythonの学習を開始

ログを書き込みました


ログファイルの内容
--------------------

[2026-05-15 15:40:09] Pythonの学習を開始
[2026-05-15 15:40:09] JSONファイルを作成
[2026-05-15 15:40:09] 学習を終了

ログファイルへ追記モードで保存して、保存完了後にログファイルを読み込んで内容を表示します。

問題7

次の2つのテキストファイル(sample1.txt、sample2.txt)を作成し、内容をプログラムで書き込みます。

sample1.txt

Python
Java
C言語
Ruby

sample2.txt

Python
JavaScript
C言語
Go

その後、2つのファイルを読み込み、同じ行と異なる行を表示するプログラムを作成してください。ファイルを1行ずつ比較して、同じ内容なら「同じ」、異なる内容なら「異なる」と表示し、かつ、行番号も表示します。

ファイルを作成しました


比較結果
--------------------

1行目

同じ

Python

--------------------

2行目

異なる

sample1.txt: Java

sample2.txt: JavaScript

--------------------

3行目

同じ

C言語

--------------------

4行目

異なる

sample1.txt: Ruby

sample2.txt: Go

--------------------

問題8

次の3つのテキストファイルを作成してください。

study1.txt
study2.txt
study3.txt

その後、カレントディレクトリに存在する「.txt」ファイルを検索し、ファイル名を「text_files.csv」に保存するプログラムを作成してください。最後にCSVファイルの内容を表示します。

テキストファイルを作成しました

CSVファイルを作成しました
ファイル名

study1.txt
study2.txt
study3.txt

問題9

「study_notes.txt」というテキストファイルを作成し、次の内容を書き込んでください。

Pythonの基本を学習する
Pythonでファイル操作を学ぶ
Javaの基本を復習する
PythonでCSVファイルを作成する

その後、「Python」というキーワードを検索し、見つかった行を「search_result.txt」に行番号も含めて保存するプログラムを作成してください。最後に結果ファイルの内容を表示します。

study_notes.txt を作成しました

検索結果を保存しました


検索結果
--------------------

1行目: Pythonの基本を学習する
2行目: Pythonでファイル操作を学ぶ
4行目: PythonでCSVファイルを作成する

上級問題(3問)

問題10

CSVファイルを利用した「ユーザー管理システム」を作成してください。

条件

  • csvモジュールを使用する
  • osモジュールを使用する
  • クラスを作成する
  • ファイル名は「users.csv」とする
  • 次の機能を実装する

機能一覧

  1. ユーザー追加
  2. ユーザー一覧表示
  3. ユーザー検索
  4. ユーザー更新
  5. ユーザー削除
  6. 平均年齢の計算
  7. CSVファイル自動作成
  8. メールアドレス重複チェック
  9. メニュー画面のループ処理
  10. エラー処理(try-except)

CSVファイルの項目

名前,年齢,メール

実行例

  1. ユーザー追加
    名前: 山田太郎
    年齢: 25
    メール: yamada@example.com
  2. ユーザー一覧表示

名前 年齢 メール
山田太郎 25 yamada@example.com

問題11

Pythonで「ファイルバックアップシステム」を作成してください。

条件

  • osモジュールを使用する
  • shutilモジュールを使用する
  • hashlibモジュールを使用する
  • jsonモジュールを使用する
  • datetimeモジュールを使用する

機能一覧

  1. backupフォルダ自動作成
  2. backup_dataフォルダ自動作成
  3. テストファイル自動生成
  4. ファイル一覧取得
  5. MD5ハッシュ計算
  6. バックアップ前後の比較
  7. 更新ファイルのみコピー
  8. サブフォルダ対応
  9. JSONへバックアップ情報保存
  10. バックアップ履歴表示
  11. バックアップ日時保存
  12. ファイルサイズ保存
  13. エラー処理

作成するテストファイル

backup_data/python.txt
backup_data/java.txt
backup_data/react.txt

実行例

バックアップ開始
バックアップ完了: python.txt
バックアップ完了: java.txt
バックアップ完了: react.txt

保存先: backup/backup_20260514_120000

テストファイルを作成しました


バックアップ開始
----------------------------------------

バックアップ完了: python.txt

バックアップ完了: java.txt

バックアップ完了: react.txt


バックアップ終了
保存先: backup/backup_20260514_075744


バックアップ履歴
----------------------------------------

backup_20260514_075744

問題12

Pythonで「Markdownファイル解析システム」を作成してください。

条件

  • reモジュールを使用する
  • jsonモジュールを使用する
  • osモジュールを使用する
  • Markdownファイルを読み込む
  • 解析結果をJSONファイルへ保存する

解析対象:sample.md の内容

# Python学習

## 基本文法

Pythonの基本を学習します。

### 変数

```python
name = "田中"
print(name)
# オブジェクト作成
analyzer = MarkdownAnalyzer()

# 実行
analyzer.run()

初級問題 解答

問題1 解答

# 「study.txt」という名前のテキストファイルを作成し、
# 次の内容を書き込みます。
#
# 1行目: Pythonの学習
# 2行目: ファイル操作の練習
# 3行目: 読み書きの基本

with open("study.txt", "w", encoding="utf-8") as file:
    file.write("1行目: Pythonの学習\n")
    file.write("2行目: ファイル操作の練習\n")
    file.write("3行目: 読み書きの基本\n")

print("study.txt を作成しました")

問題2 解答

# 「study.txt」という名前のテキストファイルを作成し、
# 7行の文章を書き込みます。
# その後、ファイルの内容をすべて表示します。

with open("study.txt", "w", encoding="utf-8") as file:
    file.write("1行目: Pythonの学習\n")
    file.write("2行目: ファイル操作の練習\n")
    file.write("3行目: 読み書きの基本\n")
    file.write("4行目: open関数の使い方\n")
    file.write("5行目: writeメソッドの練習\n")
    file.write("6行目: テキストファイルの保存\n")
    file.write("7行目: プログラミングは楽しい\n")

# ファイルを読み込んで表示
with open("study.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)

実行結果

1行目: Pythonの学習
2行目: ファイル操作の練習
3行目: 読み書きの基本
4行目: open関数の使い方
5行目: writeメソッドの練習
6行目: テキストファイルの保存
7行目: プログラミングは楽しい

問題3 解答

# study.txt の行数を数えるプログラム

line_count = 0

with open("study.txt", "r", encoding="utf-8") as file:
    for line in file:
        line_count += 1

print("行数:", line_count)

中級問題 解答

問題4 解答

# students.csv を作成してデータを書き込む

with open("students.csv", "w", encoding="utf-8") as file:
    file.write("名前,科目,点数\n")
    file.write("山田太郎,数学,85\n")
    file.write("佐藤花子,英語,92\n")
    file.write("鈴木一郎,科学,78\n")

print("students.csv を作成しました")

# CSVファイルを読み込んで表示

with open("students.csv", "r", encoding="utf-8") as file:
    for line in file:
        print(line.strip())

実行結果

students.csv を作成しました

名前,科目,点数
山田太郎,数学,85
佐藤花子,英語,92
鈴木一郎,科学,78

問題5 解答

import json

# 学生情報をディクショナリで作成
student_data = {
    "school": "Python高校",
    "class": "3年A組",
    "teacher": "田中先生",
    "students": [
        {
            "name": "山田太郎",
            "subject": "数学",
            "score": 85
        },
        {
            "name": "佐藤花子",
            "subject": "英語",
            "score": 92
        },
        {
            "name": "鈴木一郎",
            "subject": "理科",
            "score": 78
        }
    ]
}

# JSONファイルへ保存
with open("student_config.json", "w", encoding="utf-8") as file:
    json.dump(student_data, file, ensure_ascii=False, indent=4)

print("JSONファイルを保存しました")

# JSONファイルを読み込む
with open("student_config.json", "r", encoding="utf-8") as file:
    loaded_data = json.load(file)

print("\n学校名:", loaded_data["school"])
print("クラス:", loaded_data["class"])
print("担任:", loaded_data["teacher"])

print("\n生徒一覧")

for student in loaded_data["students"]:
    print("--------------------")
    print("名前:", student["name"])
    print("科目:", student["subject"])
    print("点数:", student["score"])

実行結果

JSONファイルを保存しました

学校名: Python高校
クラス: 3年A組

担任: 田中先生

生徒一覧
--------------------

名前: 山田太郎
科目: 数学
点数: 85

--------------------

名前: 佐藤花子
科目: 英語
点数: 92

--------------------

名前: 鈴木一郎
科目: 理科
点数: 78

問題6 解答

import datetime

# 現在日時を取得
now = datetime.datetime.now()

# 日時を文字列に変換
time_text = now.strftime("%Y-%m-%d %H:%M:%S")

# ログメッセージを作成
log1 = f"[{time_text}] Pythonの学習を開始\n"
log2 = f"[{time_text}] JSONファイルを作成\n"
log3 = f"[{time_text}] 学習を終了\n"

# ログファイルへ書き込む
with open("study_log.txt", "a", encoding="utf-8") as file:
    file.write(log1)
    file.write(log2)
    file.write(log3)

print("ログを書き込みました")

# ログファイルを読み込む
with open("study_log.txt", "r", encoding="utf-8") as file:
    content = file.read()

# ログ内容を表示
print("\nログファイルの内容")
print("--------------------")
print(content)

実行結果

ログを書き込みました


ログファイルの内容
--------------------

[2026-05-14 07:40:09] Pythonの学習を開始
[2026-05-14 07:40:09] JSONファイルを作成
[2026-05-14 07:40:09] 学習を終了

問題7 解答

# sample1.txt を作成

with open("sample1.txt", "w", encoding="utf-8") as file:
    file.write("Python\n")
    file.write("Java\n")
    file.write("C言語\n")
    file.write("Ruby\n")

# sample2.txt を作成

with open("sample2.txt", "w", encoding="utf-8") as file:
    file.write("Python\n")
    file.write("JavaScript\n")
    file.write("C言語\n")
    file.write("Go\n")

print("ファイルを作成しました")

# ファイルを読み込む

with open("sample1.txt", "r", encoding="utf-8") as file:
    lines1 = file.readlines()

with open("sample2.txt", "r", encoding="utf-8") as file:
    lines2 = file.readlines()

print("\n比較結果")
print("--------------------")

# 行ごとに比較

for i in range(len(lines1)):
    text1 = lines1[i].strip()
    text2 = lines2[i].strip()

    print(f"{i + 1}行目")

    if text1 == text2:
        print("同じ")
        print(text1)
    else:
        print("異なる")
        print("sample1.txt:", text1)
        print("sample2.txt:", text2)

    print("--------------------")

実行結果

ファイルを作成しました


比較結果
--------------------

1行目

同じ

Python

--------------------

2行目

異なる

sample1.txt: Java

sample2.txt: JavaScript

--------------------

3行目

同じ

C言語

--------------------

4行目

異なる

sample1.txt: Ruby

sample2.txt: Go

--------------------

問題8 解答

import os
import csv

# テキストファイルを作成

with open("study1.txt", "w", encoding="utf-8") as file:
    file.write("Python\n")

with open("study2.txt", "w", encoding="utf-8") as file:
    file.write("Java\n")

with open("study3.txt", "w", encoding="utf-8") as file:
    file.write("C言語\n")

print("テキストファイルを作成しました")

# txtファイルを探す

text_files = []

for file_name in os.listdir("."):
    if file_name.endswith(".txt"):
        text_files.append(file_name)

# CSVファイルへ保存

with open("text_files.csv", "w", encoding="utf-8", newline="") as file:
    writer = csv.writer(file)

    writer.writerow(["ファイル名"])

    for name in text_files:
        writer.writerow([name])

print("CSVファイルを作成しました")

# CSVファイルを読み込む

with open("text_files.csv", "r", encoding="utf-8") as file:
    for line in file:
        print(line.strip())

実行結果

テキストファイルを作成しました

CSVファイルを作成しました
ファイル名

study1.txt
study2.txt
study3.txt

問題9 解答

# study_notes.txt を作成

with open("study_notes.txt", "w", encoding="utf-8") as file:
    file.write("Pythonの基本を学習する\n")
    file.write("Pythonでファイル操作を学ぶ\n")
    file.write("Javaの基本を復習する\n")
    file.write("PythonでCSVファイルを作成する\n")

print("study_notes.txt を作成しました")

# 検索キーワード

keyword = "Python"

# 検索結果を保存

with open("study_notes.txt", "r", encoding="utf-8") as infile, \
     open("search_result.txt", "w", encoding="utf-8") as outfile:

    line_number = 1

    for line in infile:
        if keyword in line:
            outfile.write(f"{line_number}行目: {line}")

        line_number += 1

print("検索結果を保存しました")

# 結果ファイルを表示

print("\n検索結果")
print("--------------------")

with open("search_result.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)

実行結果

study_notes.txt を作成しました

検索結果を保存しました


検索結果
--------------------

1行目: Pythonの基本を学習する
2行目: Pythonでファイル操作を学ぶ
4行目: PythonでCSVファイルを作成する

上級問題 解答

問題10 解答

import csv
import os

class UserDatabase:

    # 1. 初期設定
    def __init__(self):
        self.file_name = "users.csv"
        self.fields = ["名前", "年齢", "メール"]

        # 2. CSVファイルが存在しなければ作成
        if not os.path.exists(self.file_name):
            with open(self.file_name, "w", encoding="utf-8", newline="") as file:
                writer = csv.writer(file)
                writer.writerow(self.fields)

    # 3. ユーザーを読み込む
    def load_users(self):
        users = []

        try:
            with open(self.file_name, "r", encoding="utf-8") as file:
                reader = csv.DictReader(file)

                for row in reader:
                    users.append(row)

        except FileNotFoundError:
            print("CSVファイルが見つかりません")

        return users

    # 4. ユーザーを保存
    def save_users(self, users):

        with open(self.file_name, "w", encoding="utf-8", newline="") as file:
            writer = csv.DictWriter(file, fieldnames=self.fields)

            writer.writeheader()

            for user in users:
                writer.writerow(user)

    # 5. ユーザー追加
    def add_user(self):

        name = input("名前: ")
        age = input("年齢: ")
        email = input("メール: ")

        users = self.load_users()

        # 6. メール重複チェック
        for user in users:
            if user["メール"] == email:
                print("このメールアドレスは登録済みです")
                return

        # 7. ユーザー情報作成
        new_user = {
            "名前": name,
            "年齢": age,
            "メール": email
        }

        # 8. リストへ追加
        users.append(new_user)

        # 9. CSVへ保存
        self.save_users(users)

        print("ユーザーを追加しました")

    # 10. 一覧表示
    def show_users(self):

        users = self.load_users()

        if len(users) == 0:
            print("ユーザーが登録されていません")
            return

        print("\nユーザー一覧")
        print("-" * 50)

        # 11. ユーザー情報表示
        for user in users:
            print(
                user["名前"],
                user["年齢"],
                user["メール"]
            )

    # 12. ユーザー検索
    def search_user(self):

        keyword = input("検索する名前: ")

        users = self.load_users()

        found = False

        # 13. 名前検索
        for user in users:

            if keyword in user["名前"]:

                print("\n検索結果")
                print(user["名前"], user["年齢"], user["メール"])

                found = True

        # 14. 見つからなかった場合
        if found == False:
            print("見つかりませんでした")

    # 15. ユーザー更新
    def update_user(self):

        email = input("更新するメールアドレス: ")

        users = self.load_users()

        updated = False

        # 16. 対象ユーザー検索
        for user in users:

            if user["メール"] == email:

                # 17. 新しい情報入力
                new_name = input("新しい名前: ")
                new_age = input("新しい年齢: ")

                # 18. 更新
                user["名前"] = new_name
                user["年齢"] = new_age

                updated = True

        # 19. 更新結果判定
        if updated:

            self.save_users(users)

            print("更新しました")

        else:
            print("メールアドレスが見つかりません")

    # 20. ユーザー削除
    def delete_user(self):

        email = input("削除するメールアドレス: ")

        users = self.load_users()

        new_users = []

        deleted = False

        # 21. 削除対象以外を保存
        for user in users:

            if user["メール"] != email:
                new_users.append(user)

            else:
                deleted = True

        # 22. CSV更新
        self.save_users(new_users)

        # 23. 削除結果表示
        if deleted:
            print("削除しました")
        else:
            print("メールアドレスが見つかりません")

    # 24. 統計情報
    def show_statistics(self):

        users = self.load_users()

        # 25. ユーザー数確認
        if len(users) == 0:
            print("ユーザーがいません")
            return

        total_age = 0

        # 26. 年齢合計
        for user in users:
            total_age += int(user["年齢"])

        # 27. 平均年齢計算
        average_age = total_age / len(users)

        print("\n統計情報")
        print("登録人数:", len(users))
        print("平均年齢:", round(average_age, 1))

    # 28. メニュー表示
    def menu(self):

        while True:

            print("\n===== ユーザー管理システム =====")
            print("1: ユーザー追加")
            print("2: ユーザー一覧")
            print("3: ユーザー検索")
            print("4: ユーザー更新")
            print("5: ユーザー削除")
            print("6: 統計情報")
            print("7: 終了")

            # 29. メニュー入力
            choice = input("番号を選択してください: ")

            # 30. メニュー判定
            if choice == "1":
                self.add_user()

            elif choice == "2":
                self.show_users()

            elif choice == "3":
                self.search_user()

            elif choice == "4":
                self.update_user()

            elif choice == "5":
                self.delete_user()

            elif choice == "6":
                self.show_statistics()

            # 31. 終了
            elif choice == "7":
                print("終了します")
                break

            # 32. エラー表示
            else:
                print("1〜7を入力してください")


# 33. オブジェクト作成
database = UserDatabase()

# 34. メニュー実行
database.menu()

問題11: ファイルバックアップシステム

import os
import shutil
import hashlib
import json
from datetime import datetime


class BackupSystem:

    # 1. 初期設定
    def __init__(self):

        # 2. バックアップ保存フォルダ
        self.backup_dir = "backup"

        # 3. 元データ保存フォルダ
        self.source_dir = "backup_data"

        # 4. マニフェストファイル
        self.manifest_file = "backup_manifest.json"

        # 5. backupフォルダ確認
        if not os.path.exists(self.backup_dir):
            os.makedirs(self.backup_dir)

        # 6. backup_dataフォルダ確認
        if not os.path.exists(self.source_dir):
            os.makedirs(self.source_dir)

    # 7. テストファイル作成
    def create_test_files(self):

        file1 = os.path.join(self.source_dir, "python.txt")
        file2 = os.path.join(self.source_dir, "java.txt")
        file3 = os.path.join(self.source_dir, "react.txt")

        with open(file1, "w", encoding="utf-8") as file:
            file.write("Python学習データ")

        with open(file2, "w", encoding="utf-8") as file:
            file.write("Java学習データ")

        with open(file3, "w", encoding="utf-8") as file:
            file.write("React学習データ")

        print("テストファイルを作成しました")

    # 8. ハッシュ計算
    def calculate_hash(self, filepath):

        md5 = hashlib.md5()

        try:
            # 9. バイナリ読み込み
            with open(filepath, "rb") as file:

                # 10. 4096バイトずつ読み込み
                while True:

                    chunk = file.read(4096)

                    # 11. 読み込み終了判定
                    if not chunk:
                        break

                    # 12. ハッシュ更新
                    md5.update(chunk)

            # 13. ハッシュ値返却
            return md5.hexdigest()

        except Exception as e:
            print("ハッシュ計算エラー:", e)
            return None

    # 14. マニフェスト読み込み
    def load_manifest(self):

        # 15. ファイル存在確認
        if os.path.exists(self.manifest_file):

            try:
                with open(self.manifest_file, "r", encoding="utf-8") as file:

                    # 16. JSON読み込み
                    data = json.load(file)

                    return data

            except Exception as e:
                print("JSON読み込みエラー:", e)

        # 17. 空データ返却
        return {}

    # 18. マニフェスト保存
    def save_manifest(self, data):

        try:
            with open(self.manifest_file, "w", encoding="utf-8") as file:

                # 19. JSON保存
                json.dump(
                    data,
                    file,
                    ensure_ascii=False,
                    indent=4
                )

        except Exception as e:
            print("JSON保存エラー:", e)

    # 20. バックアップ実行
    def backup_files(self):

        # 21. 現在日時取得
        now = datetime.now()

        # 22. 日時文字列作成
        time_text = now.strftime("%Y%m%d_%H%M%S")

        # 23. バックアップフォルダ名
        backup_folder = os.path.join(
            self.backup_dir,
            f"backup_{time_text}"
        )

        # 24. バックアップフォルダ作成
        os.makedirs(backup_folder)

        # 25. 以前のバックアップ情報
        manifest = self.load_manifest()

        # 26. 新しいバックアップ情報
        new_manifest = {}

        # 27. 元フォルダのファイル一覧取得
        files = os.listdir(self.source_dir)

        print("\nバックアップ開始")
        print("-" * 40)

        # 28. ファイルごとに処理
        for file_name in files:

            source_path = os.path.join(
                self.source_dir,
                file_name
            )

            # 29. ファイル判定
            if os.path.isfile(source_path):

                # 30. ハッシュ値取得
                file_hash = self.calculate_hash(source_path)

                # 31. 前回データ取得
                old_hash = manifest.get(file_name)

                # 32. 変更判定
                if old_hash != file_hash:

                    try:
                        # 33. コピー先パス
                        backup_path = os.path.join(
                            backup_folder,
                            file_name
                        )

                        # 34. ファイルコピー
                        shutil.copy2(
                            source_path,
                            backup_path
                        )

                        # 35. ファイルサイズ取得
                        file_size = os.path.getsize(source_path)

                        # 36. バックアップ情報保存
                        new_manifest[file_name] = {
                            "hash": file_hash,
                            "size": file_size,
                            "backup_time": time_text
                        }

                        print("バックアップ完了:", file_name)

                    except Exception as e:
                        print("コピーエラー:", e)

                else:
                    # 37. 変更なし
                    new_manifest[file_name] = old_hash

                    print("変更なし:", file_name)

        # 38. JSON保存
        self.save_manifest(new_manifest)

        # 39. 完了表示
        print("\nバックアップ終了")
        print("保存先:", backup_folder)

    # 40. バックアップ履歴表示
    def show_backup_history(self):

        print("\nバックアップ履歴")
        print("-" * 40)

        # 41. backupフォルダ一覧
        folders = os.listdir(self.backup_dir)

        found = False

        # 42. フォルダごとに表示
        for folder in folders:

            folder_path = os.path.join(
                self.backup_dir,
                folder
            )

            # 43. backup_で始まるか確認
            if folder.startswith("backup_"):

                # 44. ディレクトリ確認
                if os.path.isdir(folder_path):

                    print(folder)

                    found = True

        # 45. 履歴なし判定
        if found == False:
            print("バックアップ履歴はありません")


# 46. オブジェクト作成
system = BackupSystem()

# 47. テストファイル作成
system.create_test_files()

# 48. バックアップ実行
system.backup_files()

# 49. 履歴表示
system.show_backup_history()

実行結果:

テストファイルを作成しました


バックアップ開始
----------------------------------------

バックアップ完了: python.txt

バックアップ完了: java.txt

バックアップ完了: react.txt


バックアップ終了
保存先: backup/backup_20260514_075744


バックアップ履歴
----------------------------------------

backup_20260514_075744

問題12: マークダウンファイル解析プログラム

import re
import json
import os


class MarkdownAnalyzer:

    # 初期設定
    def __init__(self):

        # 見出し保存用
        self.headings = []

        # コードブロック保存用
        self.code_blocks = []

        # リンク保存用
        self.links = []

        # 画像保存用
        self.images = []

    # サンプルMarkdown作成
    def create_sample_markdown(self):

        markdown_text = """# Python学習

## 基本文法

Pythonの基本を学習します。

### 変数

```python
name = "田中"
print(name)

    with open(
        "sample.md",
        "w",
        encoding="utf-8"
    ) as file:

        file.write(markdown_text)

    print("sample.md を作成しました")

# Markdown読み込み
def load_markdown_file(self):

    with open(
        "sample.md",
        "r",
        encoding="utf-8"
    ) as file:

        content = file.read()

    return content

# 見出し解析
def analyze_headings(self, content):

    lines = content.split("\n")

    line_number = 1

    for line in lines:

        if line.startswith("#"):

            level = 0

            for char in line:

                if char == "#":
                    level += 1
                else:
                    break

            text = line[level:].strip()

            heading_data = {
                "level": level,
                "text": text,
                "line": line_number
            }

            self.headings.append(heading_data)

        line_number += 1

    print("見出しを解析しました")

# コードブロック解析
def analyze_code_blocks(self, content):

    pattern = r"```(\w+)\n(.*?)```"

    matches = re.finditer(
        pattern,
        content,
        re.DOTALL
    )

    for match in matches:

        language = match.group(1)

        code = match.group(2)

        line_count = len(code.split("\n"))

        code_data = {
            "language": language,
            "line_count": line_count,
            "code": code
        }

        self.code_blocks.append(code_data)

    print("コードブロックを解析しました")

# リンク解析
def analyze_links(self, content):

    pattern = r"\[([^\]]+)\]\(([^)]+)\)"

    matches = re.finditer(pattern, content)

    for match in matches:

        text = match.group(1)

        url = match.group(2)

        before_text = content[:match.start()]

        if not before_text.endswith("!"):

            link_data = {
                "text": text,
                "url": url
            }

            self.links.append(link_data)

    print("リンクを解析しました")

# 画像解析
def analyze_images(self, content):

    pattern = r"!\[([^\]]*)\]\(([^)]+)\)"

    matches = re.finditer(pattern, content)

    for match in matches:

        alt_text = match.group(1)

        url = match.group(2)

        image_data = {
            "alt_text": alt_text,
            "url": url
        }

        self.images.append(image_data)

    print("画像を解析しました")

# JSONデータ作成
def create_result_data(self):

    result = {
        "heading_count": len(self.headings),
        "code_block_count": len(self.code_blocks),
        "link_count": len(self.links),
        "image_count": len(self.images),
        "headings": self.headings,
        "code_blocks": self.code_blocks,
        "links": self.links,
        "images": self.images
    }

    return result

# JSON保存
def save_json(self, result):

    with open(
        "markdown_result.json",
        "w",
        encoding="utf-8"
    ) as file:

        json.dump(
            result,
            file,
            ensure_ascii=False,
            indent=4
        )

    print("JSONファイルを保存しました")

# 結果表示
def show_result(self, result):

    print("\n解析結果")
    print("-" * 40)

    print("見出し数:", result["heading_count"])
    print("コードブロック数:", result["code_block_count"])
    print("リンク数:", result["link_count"])
    print("画像数:", result["image_count"])

    print("\n見出し一覧")

    for heading in result["headings"]:

        print(
            "レベル:",
            heading["level"],
            "内容:",
            heading["text"]
        )

# 全体実行
def run(self):

    self.create_sample_markdown()

    content = self.load_markdown_file()

    self.analyze_headings(content)

    self.analyze_code_blocks(content)

    self.analyze_links(content)

    self.analyze_images(content)

    result = self.create_result_data()

    self.save_json(result)

    self.show_result(result)