【Python標準ライブラリ集大成 第11回】合わせ技で最強ツール開発!ファイル自動整理&バックアップスクリプトを作ろう!

「これまで学んだPythonの標準ライブラリ、どうやって組み合わせればいいんだろう?」
「実際に何か便利なものを作って、自分の成長を実感したい!」
「大量の写真やドキュメントファイル、手作業で整理するのが大変…Pythonで自動化できないかな?」

こんにちは! Python標準ライブラリ探検隊、隊長のPythonistaです! 前回はtimeモジュールとwebbrowserモジュールで、日常をちょこっと便利にする小技を学びましたね。手軽に試せる機能で、Pythonの楽しさを再発見できたのではないでしょうか。

さて、シリーズ第11回の今回は、ついにこれまでの冒険で手に入れた知識(標準ライブラリ)を総動員して、実用的な「便利ツール」作りに挑戦します! 今回作るのは、「指定したフォルダ内の画像ファイル(やドキュメントファイル)を、そのファイルの更新月ごとに自動でフォルダ分けしてコピーする、簡易バックアップ&整理ツール」です。 os, glob, shutil, datetimeといった、これまで学んできたモジュールたちが、どのように連携し、一つの目的を達成するのかを体験しましょう。少しコードは長くなるかもしれませんが、ステップバイステップで丁寧に解説していきますので、ぜひ一緒に作り上げて、大きな達成感を味わってください!


1. 今回作るツール:何をするもの?どんな問題を解決する?

私たちが今回作成する「簡易ファイルバックアップ&整理ツール」は、以下のような機能を持つことを目標とします。

  • 対象フォルダの指定: ユーザーが整理したいファイルが保存されているフォルダを指定します。
  • 対象拡張子の指定: 整理したいファイルの拡張子(例: .jpg, .png, .txt, .pdfなど)を指定します。
  • バックアップ先フォルダの指定: 整理・コピーされたファイルが保存される先の親フォルダを指定します。
  • 月別のフォルダ作成とコピー: バックアップ先フォルダ内に、ファイルの最終更新日時の「年-月」(例: 2025-05)という名前のフォルダを自動で作成し、該当するファイルをそこにコピーします。
  • (オプション)処理ログの表示: どのファイルがどこにコピーされたかなどを簡易的に表示します。

これにより、「大量のデジカメ写真が日付バラバラで一つのフォルダに溜まっている…」「ダウンロードしたPDFファイルが月ごとに整理できたらなぁ…」といった悩みを解決し、手作業でのファイル整理の手間を大幅に削減することを目指します。


2. 設計図:どんな機能が必要?どのモジュールを使う?

ツールを作る前に、必要な機能を洗い出し、それぞれにどの標準ライブラリが役立つか考えてみましょう。

  1. ユーザーからの情報入力:
    • 整理元フォルダパス、バックアップ先ベースパス、対象拡張子などをプログラムの冒頭で設定できるようにします(今回は簡単のため、コード内に直接記述する形から始めます)。
  2. 対象ファイルの検索:
    • 整理元フォルダ内で、指定された拡張子のファイルを見つけ出す。
    • 使用モジュール: glob (パターンに一致するファイルパスのリストを取得)
  3. ファイルの最終更新日時の取得と、年月フォルダ名の決定:
    • 見つかった各ファイルの最終更新日時を取得する。
    • 更新日時から「年-月」の情報を抽出し、バックアップ先のフォルダ名を決定する。
    • 使用モジュール: os.path.getmtime() (最終更新タイムスタンプ取得), datetime.fromtimestamp() (タイムスタンプをdatetimeオブジェクトに変換), datetimeオブジェクトのstrftime()メソッド (年月を文字列としてフォーマット)
  4. バックアップ先フォルダの作成:
    • バックアップ先ベースパスの下に、決定した「年-月」フォルダが存在しなければ作成する。
    • 使用モジュール: os.path.join() (パスの結合), os.path.exists() (存在確認), os.makedirs() (ディレクトリ作成、exist_ok=Trueが便利)
  5. ファイルのコピー:
    • 対象ファイルを、対応する年月フォルダにコピーする。
    • 使用モジュール: shutil.copy2() (メタデータも一緒にコピー)
  6. 処理状況の表示/記録 (今回は簡易版):
    • どのファイルがどこにコピーされたか、エラーが発生したかなどを表示する。
    • (本格的にはloggingモジュールですが、今回はprint()で代用します)

3. 実装開始!ステップ・バイ・ステップでツールを組み立てよう

それでは、上記の設計に基づいて、Pythonスクリプトを作成していきましょう。全体を一度に作ろうとせず、少しずつ関数に分けて作っていくと、見通しが良くなります。

3.1. 準備:モジュールのインポートと基本設定

import os
import glob
import shutil
from datetime import datetime # datetimeオブジェクトそのものも使うため

# --- 基本設定 (ユーザーが変更する箇所) ---
SOURCE_DIR = r"C:\Users\YourName\Pictures\ToSort"  # 例: 整理したいファイルがあるフォルダ (raw文字列推奨)
BACKUP_BASE_DIR = r"D:\Backups\SortedFiles" # 例: バックアップ先の親フォルダ
TARGET_EXTENSIONS = ["*.jpg", "*.jpeg", "*.png", "*.pdf"] # 対象とする拡張子のパターン
# ------------------------------------

def main():
    print(f"ファイル整理・バックアップ処理を開始します。")
    print(f"対象フォルダ: {SOURCE_DIR}")
    print(f"バックアップ先ベース: {BACKUP_BASE_DIR}")
    print(f"対象拡張子パターン: {TARGET_EXTENSIONS}")

    # バックアップベースディレクトリがなければ作成
    os.makedirs(BACKUP_BASE_DIR, exist_ok=True)

    processed_files_count = 0
    copied_files_count = 0

    # 指定された各拡張子パターンでファイルを検索
    for ext_pattern in TARGET_EXTENSIONS:
        search_path = os.path.join(SOURCE_DIR, ext_pattern)
        print(f"\nパターン '{search_path}' でファイルを検索中...")
        
        file_list = glob.glob(search_path)
        
        if not file_list:
            print(f"  パターン '{ext_pattern}' に一致するファイルは見つかりませんでした。")
            continue

        for source_file_path in file_list:
            processed_files_count += 1
            try:
                # ファイルの最終更新日時を取得
                timestamp = os.path.getmtime(source_file_path)
                dt_object = datetime.fromtimestamp(timestamp)
                
                # 年-月のフォルダ名を決定 (例: "2025-05")
                year_month_folder_name = dt_object.strftime("%Y-%m")
                
                # バックアップ先のフルパスを作成
                destination_folder_path = os.path.join(BACKUP_BASE_DIR, year_month_folder_name)
                os.makedirs(destination_folder_path, exist_ok=True) # 年月フォルダがなければ作成
                
                # コピー先のファイルパスを決定 (ファイル名は元のまま)
                destination_file_path = os.path.join(destination_folder_path, os.path.basename(source_file_path))
                
                # ファイルをコピー (既に存在する場合は上書きしないようにする場合は、ここで存在確認が必要)
                if not os.path.exists(destination_file_path):
                    shutil.copy2(source_file_path, destination_file_path) # copy2でメタデータも保持
                    print(f"  コピー完了: {source_file_path} -> {destination_file_path}")
                    copied_files_count += 1
                else:
                    print(f"  スキップ: {destination_file_path} は既に存在します。")

            except Exception as e:
                print(f"  エラー: {source_file_path} の処理中に問題が発生 - {e}")

    print(f"\n処理が完了しました。")
    print(f"処理対象ファイル数: {processed_files_count}")
    print(f"実際にコピーされたファイル数: {copied_files_count}")

# スクリプトとして実行された場合にmain()関数を呼び出す
if __name__ == "__main__":
    main()

コードのポイント解説:

  • 基本設定: SOURCE_DIR, BACKUP_BASE_DIR, TARGET_EXTENSIONS を自分の環境に合わせて変更します。Windowsのパスはr"C:\..."のようにraw文字列で書くとバックスラッシュのエスケープを気にしなくて済みます。
  • os.makedirs(..., exist_ok=True): バックアップ先の親ディレクトリや、年月ごとのサブディレクトリを作成する際に、既に存在していてもエラーにならないようにしています。
  • glob.glob(os.path.join(SOURCE_DIR, ext_pattern)): os.path.join()を使って、OSに依存しない形で検索パターン用のパス文字列を組み立てています。
  • os.path.getmtime()datetime.fromtimestamp(): ファイルの最終更新時刻(Unixタイムスタンプ)を取得し、それを人間が扱いやすいdatetimeオブジェクトに変換しています。
  • dt_object.strftime("%Y-%m"): datetimeオブジェクトから「年-月」の形式の文字列(例: "2025-05")を生成し、フォルダ名としています。
  • shutil.copy2(): ファイルをコピーします。copy2は元のファイルのメタデータ(作成日時や更新日時など)も可能な限り保持してコピーしようとします。
  • 簡単なエラーハンドリング: try-exceptブロックで、ファイルの処理中に何か問題が発生した場合でも、プログラム全体が停止しないようにしています。
  • if __name__ == "__main__":: このスクリプトが直接実行された場合にのみmain()関数を呼び出すためのお決まりの記述です。

3.2. 使い方と実行例

  1. 上記のコードをPythonファイル(例: file_organizer.py)として保存します。
  2. コード内のSOURCE_DIR, BACKUP_BASE_DIR, TARGET_EXTENSIONSをあなたの環境に合わせて編集します。
  3. コマンドプロンプトやターミナルで、そのファイルを保存したディレクトリに移動し、python file_organizer.py を実行します。
  4. 処理が開始され、対象ファイルがバックアップ先に年月ごとのフォルダに分類されてコピーされます。コンソールには処理状況が表示されます。

(注意)このスクリプトはファイルをコピーするものです。移動(元のファイルを削除)するものではありません。また、テストは必ずコピーしても問題ないファイルやフォルダで行ってください。


4. さらなる改善点・拡張のアイデア

今回のツールは基本的な機能に絞りましたが、さらに以下のような改善や機能追加も考えられます。

  • 設定ファイル化: SOURCE_DIRなどの設定を、jsonファイルやcsvファイルから読み込むようにする。
  • 移動オプション: コピーではなく、ファイルを移動するオプションを追加する(shutil.move()を使用。元のファイルが消えるのでより慎重な扱いが必要)。
  • 詳細なログ出力: loggingモジュールを使って、処理内容やエラーを詳細なログファイルに記録する。
  • GUIの追加: Tkinter(標準ライブラリ)やPySimpleGUI(外部ライブラリ)などを使って、グラフィカルなインターフェースを追加する。
  • Exif情報からの日付取得(画像の場合): 画像ファイルのExif情報(撮影日時など)を読み取り、それに基づいてフォルダ分けする(これにはPillowなどの外部ライブラリが必要になります)。
  • 重複ファイルのチェック: コピー先に既に同じ内容のファイルが存在する場合の処理(スキップ、上書き、リネームなど)をより細かく制御する。

まとめ:標準ライブラリの組み合わせで、アイデアを形に!

今回は、Python標準ライブラリ解説シリーズの集大成として、これまでに学んだ複数のモジュール(os, glob, shutil, datetime)を組み合わせて、実用的な「簡易ファイルバックアップ&整理ツール」を作成しました。

このプロジェクトを通して、

  • 各標準ライブラリが持つ個々の機能
  • それらをどのように連携させれば、より複雑なタスクを達成できるか
  • プログラムを機能ごとに分割し、ステップバイステップで開発を進める考え方

といった点を体験していただけたのではないでしょうか。

標準ライブラリだけでも、アイデア次第で様々な便利なツールや自動化スクリプトを作成することができます。今回のツールをベースに、ぜひあなた自身のニーズに合わせてカスタマイズしたり、新しい機能を追加したりしてみてください。

これで、Python標準ライブラリ探検隊の主要な冒険は一段落です。しかし、Pythonの世界はまだまだ広く、深く、面白い発見に満ちています。このシリーズが、皆さんのPython学習の旅の一助となれば幸いです。

次回はシリーズの総まとめと、皆さんの「次なる冒険」へのヒントをお届けしたいと思います!

その他の投稿はこちら

コメント

このブログの人気の投稿

タイトルまとめ

これで迷わない!WindowsでPython環境構築する一番やさしい方法 #0

【Python標準ライブラリ完結!】11の冒険をありがとう!君のPython力が飛躍する「次の一歩」とは? 🚀