【Python】TyperとRichで重複ファイル整理ツールを作ってみた

【Python】TyperとRichで重複ファイル整理ツールを作ってみた

公開: 更新:
CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座

パソコンの中にいつの間にか増える「中身が同じファイル」を、名前ではなく内容で見つけて整理します。そこでPythonのTyperでコマンドを組み立て、Richで結果を色付きの表に見せる重複ファイル整理ツールを作ってみました。

中核はSHA-256ハッシュによる内容照合で、seedscanorganizeの3つのサブコマンドを使い「サンプル生成→重複表示→退避」まで一通り動かせます。初心者でも追体験できるよう、コードを断片ごとに噛み砕いて解説していきます。

Typerの基本概念、要件定義、実装、動作確認までを順番に学べる構成です。動画は目次から確認したい場面へ移動でき、本文だけでも手順と考え方が完結します。

【Python】TyperとRichで重複ファイル整理ツールを作ってみた|フルカリキュラム|概要・完成挙動
動画の内容をテキストで確認する

オープニング。TyperとRichを使って重複ファイル整理CLIを作るカリキュラムを始めます。概要紹介。

TyperとRichの役割と使い方を学ぶ 重複ファイル整理CLIの要件を整理する 完成コードと実行結果を確認する 最後に実コマンドとファイル状態で完成挙動を確かめる 具体的にやること。内容が同じファイルを検出する 重複を色付きの表で一覧する お試し用のサンプルを生成する 余分なコピーを移動先へ整理する 各グループの原本を1つ残す 実装環境・必須アプリ。

OS:Windows 11 Pro Python:3.13.3シェル:PowerShell 5.1必須アプリ:コードエディター、ターミナル、エクスプローラー パッケージ:pip、typer、rich TyperとRichとは。

PythonでCLIを作るライブラリのTyper:関数をそのままコマンドにできる 結果を見やすく表示するライブラリのRich:表を組んで整然と見せる TyperとRichで重複ファイル整理CLIを作る際の重要ポイント。SHA-256で内容を要約する 同じハッシュを同一内容とみなす 大きなファイルはチャンクで読む 重複ファイル整理CLIの要件定義。

seedで6個のサンプルが作られるscanで重複グループが表に並ぶ 重複がなければその旨を知らせるorganizeで原本が残りコピーが移動する 最後に移動件数が表示される 確認1/3: サンプルファイルを作成する。seedコマンドを実行し、重複を含む6個のサンプルファイルが作成される様子を確認します。確認2/3: 重複ファイルを一覧する。

scanコマンドを実行し、同じ内容のファイルと余分なコピーの件数を表で確認します。確認2/3: 重複ファイルを一覧する。scanコマンドを実行し、同じ内容のファイルと余分なコピーの件数を表で確認します。

確認3/3: 余分なコピーを安全に移動する。organizeコマンドを実行し、原本を残して余分なコピーだけが退避される結果を確認します。確認3/3: 余分なコピーを安全に移動する。

organizeコマンドを実行し、原本を残して余分なコピーだけが退避される結果を確認します。学習内容のまとめ。関数をそのままコマンドにできる 表を組んで整然と見せるSHA-256で内容を要約する 名前ではなく内容で判定する 小さく実行確認しながら完成状態まで段階的に組み立てる エンディング。

Python研修はCodeCampでご確認ください。

TyperとRichとは

今回使用する主要なライブラリについて、役割と使い分けを順番に確認します。

CLIを作るライブラリのTyper

Typerは、Pythonの関数をそのままコマンドラインツールに変えられるライブラリです。引数の型ヒントを書くだけで入力の受け取りやヘルプ表示を自動で用意してくれるため、コマンドの骨組みづくりに集中できます。今回のツールでも、seedとscanとorganizeという3つの関数がそのままサブコマンドになっています。

難しい設定を書かずにCLIを組み立てられる点が、初心者にとって大きな魅力といえるでしょう。

  • 関数をそのままコマンドにできる
  • 型ヒントから引数を自動解釈する
  • ヘルプを自動生成する
  • 複数のサブコマンドをまとめられる

結果を見やすく表示するライブラリのRich

Richは、ターミナルの出力を色付きの文字や整った表で見せられるライブラリです。標準のprintでは味気ない実行結果も、Consoleオブジェクトを通せば重要な部分を強調できます。このツールでは重複ファイルの一覧をTableで組み立て、グループ番号やハッシュを列ごとに整理して表示しています。

結果が読みやすくなり、どのファイルが重複しているのかを一目で把握できるでしょう。

  • 表を組んで整然と見せる
  • 色やスタイルを文字に付ける
  • Consoleオブジェクトで出力する
さらに詳しく学べるPython研修の詳細はこちら

Python・Typerで開発する場合の環境構築

この記事のセットアップ手順と掲載コードは、Windows 11 Pro、PowerShell 5.1、Python 3.13.3、Typer 0.27.0で動作確認しています。仮想環境を有効化せず、その中のPythonを直接指定するため、以下のコマンドはPowerShellとコマンドプロンプト(cmd)の両方で使えます。

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install typer rich

macOS・Linuxでは仮想環境内のPythonパスが異なります。今回の動作確認環境とは異なるため、以下は環境差分を補う参考手順です。

python3 -m venv .venv
./.venv/bin/python -m pip install --upgrade pip
./.venv/bin/python -m pip install typer rich
  • typerを入れるとrichも依存として入りますが、Richを明示的に使うので併記して導入しています。
  • organizeの--destは走査対象フォルダの外側(例: ./duplicates)を指定すると、整理後のscanで移動済みコピーを拾わずに済みます。
さらに詳しく学べるPython研修の詳細はこちら

PythonのTyperとRichで作る重複ファイル整理CLIの要件定義

目的は、内容が同じファイルをハッシュで見つけて整理することです。

対象者として、PythonでCLIツールの作り方を学びたい人を想定しています。

完成物は、TyperとRichで作る重複ファイル整理CLIです。

実装へ入る前に、機能・品質・受け入れ条件を分けて確認します。

機能要件

  • 内容が同じファイルを検出する
  • 重複を色付きの表で一覧する
  • お試し用のサンプルを生成する
  • 余分なコピーを移動先へ整理する
  • 各グループの原本を1つ残す
  • 移動先フォルダを指定できる

非機能要件

  • 名前ではなく内容で判定する
  • 大きなファイルもチャンク読みで扱える
  • 3つのサブコマンドで操作を分ける
  • 標準ライブラリ中心で構成する

実装方針

今回はTyperとRichの基本動作を追いやすくするため、重複ファイル整理CLI本体を1つのPythonファイルへまとめます。

入力、判定、結果表示の役割を分け、実行結果を確認しながら機能を積み上げます。

  • TyperとRichのコマンド定義と処理関数の責務を分ける
  • 入力フォルダやオプションを検証してからファイル処理を始める
  • 時間のかかる処理は進捗を表示し、結果を確認できるようにする
  • 削除ではなく退避を選び、誤判定から戻せる設計にする

完成と判断する条件

  1. seedで6個のサンプルが作られる
  2. scanで重複グループが表に並ぶ
  3. 重複がなければその旨を知らせる
  4. organizeで原本が残りコピーが移動する
  5. 最後に移動件数が表示される
さらに詳しく学べるPython研修の詳細はこちら

TyperとRichで重複ファイル整理CLIを作る際の重要ポイント

このツールの心臓部は、ファイルの内容をSHA-256というハッシュ値に要約して比べる仕組みです。名前や場所が違っても中身が同じならば同じハッシュになるため、コピーを確実に見つけ出せます。大きなファイルでもメモリを圧迫しないよう、内容を少しずつ読み込みながら計算していく点も工夫のひとつでしょう。

整理の場面では各グループの先頭を原本として残し、余分なコピーだけを移動先へ退避させています。

  • SHA-256で内容を要約する
  • 同じハッシュを同一内容とみなす
  • 大きなファイルはチャンクで読む
  • 原本を1つ残しコピーを退避する

ハッシュで内容を比べる理由

ファイル名やサイズだけでは、本当に中身が同じかどうかは判断できません。SHA-256はファイルの内容から一意の文字列を生成するので、この値が一致すれば内容も同じだと安心して扱えます。

  • 名前では同一と断定できない
  • 内容から一意の値を作る
  • 値の一致で重複を判定する

重複グループのまとめ方

defaultdictを使い、同じハッシュを持つファイルを一つのリストへ集めていきます。集計後に要素が2つ以上あるものだけを残せば、重複しているグループだけを取り出せます。

  • ハッシュをキーに集約する
  • 2件以上を重複とみなす
  • 単独のファイルは除外する

原本を残して整理する流れ

各グループの先頭を原本として残し、残りのコピーだけを移動先へ動かします。移動先に同名のファイルがある場合は連番を付け、既存のファイルを上書きしないよう配慮しています。

  • 先頭を原本として残す
  • 余りを移動先へ動かす
  • 同名は連番で退避する

Python研修一覧はこちら

目的に合うPython研修を一覧形式から探したい方は、ぜひご利用ください。

Python研修を比較する

Java研修一覧はこちら

目的に合うJava研修を一覧形式から探したい方は、ぜひご利用ください。

Java研修を比較する

PHP研修一覧はこちら

目的に合うPHP研修を一覧形式から探したい方は、ぜひご利用ください。

PHP研修を比較する

新入社員研修

目的に合う新入社員研修を一覧形式から探したい方は、ぜひご利用ください。

新入社員研修を比較する

全ての研修からも探したい方はこちら

PythonのTyperとRichで作る重複ファイル整理CLIの完成コード

00:00 / 10:31
【Python】TyperとRichで重複ファイル整理ツールを作ってみた|フルカリキュラム|コード実装
動画の内容をテキストで確認する

INTRO: Typerを使ったCLI開発を開始。コードを1行ずつ入力し、節目ごとに実行結果を確かめながら完成させます。LINE 001: hashlibの読み込み。

ファイルの中身からハッシュ値を計算するための標準ライブラリhashlibを読み込みます。後半のcompute_hash関数で、同じ内容かどうかを見分けるために使います。LINE 002: shutilの読み込み。

ファイルのコピーや移動を扱う標準ライブラリshutilを読み込みます。organizeコマンドで余分なコピーを別フォルダへ移すときに利用します。LINE 003: defaultdictの読み込み。

存在しないキーにも自動で初期値を用意してくれるdefaultdictを読み込みます。ハッシュ値ごとにファイルの一覧をまとめる処理を短く書くために使います。LINE 004: Pathの読み込み。

ファイルやフォルダの場所をオブジェクトとして扱えるPathを読み込みます。パスの結合や再帰的な走査を、文字列操作より安全に書けるようになります。LINE 006: Typerの読み込み。

コマンドライン用のツールを手軽に作れるライブラリtyperを読み込みます。このあとseedやscanといったサブコマンドを定義する土台になります。LINE 007: Consoleの読み込み。

Richの装飾付き表示を担うConsoleクラスを読み込みます。色付きのメッセージや表をターミナルにきれいに出力するために使います。LINE 008: Tableの読み込み。

Richで整った罫線付きの表を作るTableクラスを読み込みます。scanやorganizeの結果を見やすい一覧にして見せるのに役立ちます。LINE 010: アプリ本体の作成。

typer.Typerでツール全体の本体を作ります。add_completion=Falseで補完機能を省き、helpにはツールの説明文を設定しています。LINE 011: コンソールの準備。

画面出力に使うConsoleオブジェクトを一つ作り、consoleという名前で共有します。以降はこれを通じて色付きメッセージや表を表示します。RUN 1/7: TyperのappとRichのConsoleを準備する。

importと初期化が終わり、コマンドを束ねるappと出力を担うconsoleが用意できた段階です。まだコマンドはありませんが、オブジェクトが正しく作れているかを確認できます。CHECK 1/7: 途中実行に成功。

app: Typer console: Console LINE 014: ハッシュ計算の節の説明。ここからはファイルの中身をハッシュ値に変換する関数を定義します。大きなファイルでも一度に全部読まず、少しずつ読む工夫をする点を示しています。

LINE 015: compute_hash関数の定義。ファイルのパスを受け取ってハッシュ値の文字列を返すcompute_hash関数を定義します。chunk_sizeは一度に読み込むバイト数で、初期値は65536バイトです。

LINE 016: ハッシュ計算器の用意。SHA-256方式でハッシュを計算するためのオブジェクトをdigestとして作ります。このあとファイルの中身を少しずつ渡して、最終的な値を組み立てます。

LINE 017: ファイルをバイナリで開く。対象のファイルを"rb"モードで開き、変数fとして扱います。バイナリで読むことで、テキストでも画像でも同じ方法で中身を処理できます。

LINE 018: チャンク単位の繰り返し。iterを使い、ファイルからchunk_size分ずつ読み取ってchunkに取り出す繰り返しを作ります。空のバイト列b""が返ったら読み終わりとして自動で止まります。

LINE 019: ハッシュへの取り込み。読み込んだ一区切り分のデータをdigestに渡して、ハッシュの計算を少しずつ進めます。この積み重ねでファイル全体の特徴を一つの値にまとめます。

LINE 020: ハッシュ値の返却。計算し終えたハッシュ値を、扱いやすい16進数の文字列に変換して返します。この文字列が、ファイルの中身を見分けるための指紋の役割を果たします。

RUN 2/7: ファイルのハッシュ計算を実装する。compute_hash関数が完成し、ファイルの内容からSHA-256の値を求められるようになりました。試しに小さなファイルを作り、ハッシュの先頭だけを表示して動きを確かめます。

CHECK 2/7: 途中実行に成功。hash: 2cf24dba5f LINE 023: 重複検出の節の説明。ここからは、内容がまったく同じファイルを一つのグループにまとめる関数を作ります。

ハッシュ値が一致するものを重複とみなす方針を示しています。LINE 024: find_duplicate_groups関数の定義。調べたいフォルダを受け取り、ハッシュ値をキーにファイル一覧を値とする辞書を返す関数を定義します。

この結果が各コマンドの重複判定のもとになります。LINE 025: 集計用辞書の用意。ハッシュ値ごとにファイルをまとめるための辞書hashesを、defaultdict(list)で用意します。

新しいハッシュ値が出てきても、自動で空のリストが割り当てられます。LINE 026: フォルダの再帰走査。rglobで指定フォルダの中身をサブフォルダまで含めてたどり、sortedで順番をそろえて一つずつpathに取り出します。

並べ替えることで結果の順序が毎回安定します。LINE 027: ファイルかどうかの判定。取り出したpathがフォルダではなくファイルであるかをis_fileで確認します。

ファイルのときだけ次のハッシュ計算へ進めます。LINE 028: ハッシュごとの振り分け。compute_hashでそのファイルのハッシュ値を求め、同じ値のリストにパスを追加します。

これで中身が同じファイルが自然と同じグループに集まります。LINE 029: 重複グループの絞り込み。集めた辞書のうち、ファイルが2つ以上ある項目だけを残して返します。

1つしかないものは重複ではないため、ここで除外しています。RUN 3/7: 重複グループを検出する処理を加える。find_duplicate_groupsが加わり、フォルダ内の同一内容ファイルをまとめられるようになりました。

中身が同じ2つのファイルを置き、検出されるグループ数を数えて確かめます。CHECK 3/7: 途中実行に成功。groups: 1 LINE 032: サンプル生成の節の説明。

ここからは、動作を試すための重複入りサンプルを作るコマンドを用意します。手元にファイルがなくてもすぐツールを体験できるようにする目的です。LINE 033: コマンドとしての登録。

@app.commandを付けて、次に定義する関数をツールのサブコマンドとして登録します。これでコマンドラインからseedとして呼び出せるようになります。LINE 034: seedコマンドの定義。

サンプルを作る先のフォルダを引数として受け

コードは、ハッシュ計算とグループ検出という2つの部品を土台に、3つのサブコマンドをかぶせる構成にしています。

compute_hashfind_duplicate_groupsが中核のロジックで、seedscanorganizeはそれらを呼び出す薄い入り口という役割分担です。

表示まわりはRichのConsoleTableに任せ、ファイルの移動は標準ライブラリのshutilに委ねました。以降で押さえるべき要点だけを断片ごとに見ていきます。

このセクションの用語

defaultdict
存在しないキーへアクセスすると自動で初期値(ここでは空リスト)を用意してくれる辞書です。追加処理を短く書けます。
rglob
Pathのメソッドで、サブフォルダも含めて再帰的にファイルを列挙します。
shutil
ファイルのコピーや移動をまとめて扱えるPython標準ライブラリです。ここではshutil.moveで退避に使います。
ファイルからハッシュ、グループ化までのデータの流れ rglobでファイル一覧を取得compute_hashでダイジェスト計算defaultdictにハッシュ別へ格納2件以上のグループを抽出Tableで表示 / shutil.moveで退避
ファイルからハッシュ、グループ化までのデータの流れ
import hashlib
import shutil
from collections import defaultdict
from pathlib import Path

import typer
from rich.console import Console
from rich.table import Table

app = typer.Typer(add_completion=False, help="TyperとRichで作る重複ファイル整理ツール")
console = Console()


# ファイルのハッシュ計算(チャンク読みで大きなファイルにも対応)
def compute_hash(path: Path, chunk_size: int = 65536) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as f:
        for chunk in iter(lambda: f.read(chunk_size), b""):
            digest.update(chunk)
    return digest.hexdigest()


# 重複グループの検出(内容が同一のファイルをまとめる)
def find_duplicate_groups(directory: Path) -> dict[str, list[Path]]:
    hashes: dict[str, list[Path]] = defaultdict(list)
    for path in sorted(directory.rglob("*")):
        if path.is_file():
            hashes[compute_hash(path)].append(path)
    return {h: paths for h, paths in hashes.items() if len(paths) > 1}


# お試し用サンプルの生成
@app.command()
def seed(directory: Path = typer.Argument(..., help="サンプルを作成するフォルダ")):
    """重複を含むサンプルファイルを作成し、ツールをすぐ試せるようにする。"""
    directory.mkdir(parents=True, exist_ok=True)
    (directory / "backup").mkdir(exist_ok=True)
    samples = {
        "report.txt": "四半期の売上レポート\n",
        "report_copy.txt": "四半期の売上レポート\n",
        "logo.dat": "BINARY-LOGO-DATA",
        "backup/logo.dat": "BINARY-LOGO-DATA",
        "backup/report_bak.txt": "四半期の売上レポート\n",
        "notes.txt": "重複しない個別のメモ\n",
    }
    for rel, content in samples.items():
        (directory / rel).write_text(content, encoding="utf-8")
    console.print(f"[green]サンプルを作成しました[/]: {directory} に {len(samples)} 個のファイル")


# 重複ファイルの一覧表示
@app.command()
def scan(directory: Path = typer.Argument(..., help="走査するフォルダ")):
    """フォルダを再帰的に走査し、重複ファイルを表にして表示する。"""
    groups = find_duplicate_groups(directory)
    if not groups:
        console.print(f"[green]重複はありません[/]: {directory}")
        raise typer.Exit()

    table = Table(title=f"重複ファイル: {directory}")
    table.add_column("グループ", justify="right", style="cyan")
    table.add_column("ハッシュ", style="magenta")
    table.add_column("サイズ", justify="right")
    table.add_column("ファイル")
    for i, (h, paths) in enumerate(groups.items(), start=1):
        size = paths[0].stat().st_size
        files = "\n".join(str(p) for p in paths)
        table.add_row(str(i), h[:10], f"{size} B", files)
    console.print(table)

    extra = sum(len(paths) - 1 for paths in groups.values())
    console.print(f"[yellow]余分なコピー: {extra} 件[/]")


# 重複ファイルの整理(原本を1つ残し、コピーを移動)
@app.command()
def organize(
    directory: Path = typer.Argument(..., help="整理するフォルダ"),
    dest: Path = typer.Option("duplicates", "--dest", "-d", help="コピーの移動先フォルダ"),
):
    """各グループで最初の1つを原本として残し、余分なコピーを移動先へ整理する。"""
    groups = find_duplicate_groups(directory)
    if not groups:
        console.print(f"[green]整理する重複はありません[/]: {directory}")
        raise typer.Exit()

    dest.mkdir(parents=True, exist_ok=True)
    moved = 0
    table = Table(title="整理結果")
    table.add_column("残した原本", style="green")
    table.add_column("移動したコピー", style="yellow")
    for paths in groups.values():
        keep, *copies = paths
        for copy in copies:
            target = dest / copy.name
            counter = 1
            while target.exists():
                target = dest / f"{copy.stem}_{counter}{copy.suffix}"
                counter += 1
            shutil.move(str(copy), str(target))
            table.add_row(str(keep), str(target))
            moved += 1
    console.print(table)
    console.print(f"[green]{moved} 件のコピーを {dest} へ移動しました[/]")


if __name__ == "__main__":
    app()

コード全文は上の折り畳みに入れてあるので、全部を上から読む必要はありません。ここでは特に重要な部分だけを抜き出して、何をしているのか順番に見ていきます。

typer.Typerでアプリの土台を作る

app = typer.Typer(add_completion=False, help="TyperとRichで作る重複ファイル整理ツール")
console = Console()

typer.Typer()でコマンドをぶら下げる本体を1つ用意します。ここに@app.command()で各機能を登録していく形です。RichのConsoleも先に作っておき、色付き出力の窓口として使い回します。

compute_hashでチャンク読みしながらSHA-256を求める

digest = hashlib.sha256()
with path.open("rb") as f:
    for chunk in iter(lambda: f.read(chunk_size), b""):
        digest.update(chunk)
return digest.hexdigest()

ファイルをバイナリで開き、chunk_sizeずつ小分けに読みながらハッシュへ流し込みます。巨大なファイルでも一度に全部メモリへ載せないので安全です。最後にhexdigest()で16進の文字列に変換して返します。

find_duplicate_groupsでハッシュ別にまとめる

hashes: dict[str, list[Path]] = defaultdict(list)
for path in sorted(directory.rglob("*")):
    if path.is_file():
        hashes[compute_hash(path)].append(path)
return {h: paths for h, paths in hashes.items() if len(paths) > 1}

rglob("*")でサブフォルダまで走査し、ファイルだけをハッシュ値をキーにした辞書へ振り分けます。defaultdictのおかげで初期化を気にせず追加できるのが便利です。最後に、同じキーが2件以上ある組だけを重複として絞り込んで返します。

RichのTableで列を定義する

table = Table(title=f"重複ファイル: {directory}")
table.add_column("グループ", justify="right", style="cyan")
table.add_column("ハッシュ", style="magenta")
table.add_column("サイズ", justify="right")
table.add_column("ファイル")

Tableを作り、add_columnで列の見出し・寄せ方向・色を1つずつ設定します。styleにcyanやmagentaを指定するだけで、ターミナルに色付きの表が描けるのがRichの強みです。

add_rowで重複グループを1行ずつ表に流し込む

for i, (h, paths) in enumerate(groups.items(), start=1):
    size = paths[0].stat().st_size
    files = "\n".join(str(p) for p in paths)
    table.add_row(str(i), h[:10], f"{size} B", files)

enumerateで1から始まる通し番号を振りながら、各グループを1行として追加します。h[:10]でハッシュを先頭10文字に短縮し、stat().st_sizeでファイルサイズを取得しました。複数のパスは改行でつないで1つのセルに収めています。

seedコマンドで重複入りサンプルを用意する

samples = {
    "report.txt": "四半期の売上レポート\n",
    "report_copy.txt": "四半期の売上レポート\n",
    "logo.dat": "BINARY-LOGO-DATA",
    "backup/logo.dat": "BINARY-LOGO-DATA",
}

名前は違っても中身が同じファイルをわざと混ぜたサンプルを書き出します。これで環境を汚さずにscanorganizeの挙動をすぐ試せます。まずseedで試して感覚をつかむのがおすすめです。


Python基礎・実践(Django)

企業・法人向けのPython研修では、基礎から応用まで体系的に学べます。

Python研修の詳細

DX社員研修

企業・法人向けのDX研修では、実務に繋がるリスキリングでITレベルを向上させます。

DX研修の詳細

Javaエンジニア育成研修

企業・法人向けのJavaエンジニア育成研修では、Javaの基礎から応用まで確実に習得できます。

Java研修の詳細

新卒・新入社員向け研修

企業・法人に新入社員・新卒社員に向けたプログラミング研修を提供しています。

新入社員研修の詳細

コードキャンプのIT研修を全て見る

PythonのTyperとRichで作った重複ファイル整理CLIの動作確認

実際にCLIツールを4回のコマンドで実行し、いずれも終了コード0で正常に動作しました。

まずpython subject.py seed ./sample_filesでサンプルを生成し、続けてscanで重複を一覧表示しています。

そのあとpython subject.py organize ./sample_files --dest ./duplicatesで重複コピーを退避し、最後にもう一度scanして重複が解消されたことを確認できました。

scanではRichの色付きテーブルにグループ番号・短縮ハッシュ・サイズ・ファイル一覧が並び、余分なコピー件数もまとめて表示されます。

このセクションの用語

終了コード
コマンドが終わったときに返す番号です。0は正常終了を表し、0以外は何らかのエラーを示します。
python subject.py seed ./sample_filesの実行結果(終了コード0)
python subject.py seed ./sample_filesの実行結果(終了コード0)
python subject.py scan ./sample_filesの実行結果(終了コード0)
python subject.py scan ./sample_filesの実行結果(終了コード0)
python subject.py organize ./sample_files --dest ./duplicatesの実行結果(終了コード0)
python subject.py organize ./sample_files --dest ./duplicatesの実行結果(終了コード0)
python subject.py scan ./sample_filesの実行結果(終了コード0)
python subject.py scan ./sample_filesの実行結果(終了コード0)
さらに詳しく学べるPython研修の詳細はこちら

PythonのTyperとRich利用時に起きやすいエラーと対処法

初心者が最初につまずきやすいのは、ライブラリの導入漏れと引数の渡し忘れです。

代表的なエラーと、その原因・対処を表にまとめました。メッセージの文言を手がかりに落ち着いて切り分けるのがコツです。

エラー例 原因 対処
ModuleNotFoundError: No module named 'typer' TyperやRichが未インストール pip install typer richで導入する
TypeError: 'type' object is not subscriptable dict[str, list[Path]]の記法が古いPythonで動かない Python3.9以上を使うかfrom __future__ import annotationsを追加する
FileNotFoundError 存在しないフォルダを引数に渡した パスの綴りを確認し、先にseedでフォルダを作る
PermissionError 対象や移動先が使用中、または書き込み権限がない ファイルを閉じ、権限のある場所を--destに指定する
Error: Missing argument 'DIRECTORY' 対象フォルダの引数を渡し忘れた python subject.py scan ./sample_filesのように指定する

重複ファイル整理CLIで注意したい点

organizeは重複と判定したファイルを指定先へ移動します。仕組みを理解しないまま実行すると、残したいファイルまで移動するおそれがあるため、事前に動作の前提を確認しておくことが大切です。

ポイントとしては、重複の判定基準、原本の決まり方、チャンク読みの3点を押さえておきましょう。

POINT

判定基準:SHA-256で内容の同一性

原本:各重複グループの先頭を保持

読み込み:チャンク単位で内容を取得

さらに詳しく学べるPython研修の詳細はこちら

重複ファイル整理ツールが活躍する場面

内容照合という仕組みは、名前がバラバラでも中身が同じファイルを見つけたい場面で効きます。

実務で応用しやすい使い方を、具体的な手順まで踏み込んで挙げてみます。

使える場面 具体的な使い方
写真・画像フォルダの整理 何度も取り込んで増えた同一画像をscanで洗い出し、organizeで退避してから中身を確認して削除する
ダウンロードフォルダの掃除 「(1)」付きで二重保存された資料やインストーラを内容照合で見つけ、原本だけ残す
バックアップの重複除去 複数世代のバックアップ間で中身が同じファイルを検出し、ストレージの無駄を可視化する
納品データの重複チェック 納品前フォルダをscanし、同一内容のファイルが混在していないか色付きの表で目視確認する
さらに詳しく学べるPython研修の詳細はこちら

PythonのTyperとRichによる重複ファイル整理CLI開発のまとめ

TyperとRichを組み合わせると、少ないコードで「使いやすいコマンド」と「見やすい表示」を両立できました。

中核はSHA-256による内容照合というシンプルな発想で、compute_hashfind_duplicate_groupsさえ理解すれば全体像がつかめます。

まずはseedで作ったサンプルで挙動を確かめ、慣れてきたら自分のフォルダへ少しずつ適用してみてください。

さらに詳しく学べるPython研修の詳細はこちら

参考にした一次情報

  1. ^ Typer公式ドキュメント(サブコマンドの作り方). https://typer.tiangolo.com/, (参照26-07-20).
  2. ^ Rich公式ドキュメント(Tableによる表表示). https://rich.readthedocs.io/en/stable/tables.html, (参照26-07-20).
  3. ^ Python公式ドキュメントhashlib(SHA-256などのハッシュ計算). https://docs.python.org/ja/3/library/hashlib.html, (参照26-07-20).
  4. ^ Python公式ドキュメントshutil(ファイルの移動shutil.move). https://docs.python.org/ja/3/library/shutil.html, (参照26-07-20).

※内容は執筆時点のものです。ライブラリやサイトの仕様は変わる可能性があるため、公式ドキュメントもあわせてご確認ください。

ITやプログラミングに関するコラム


ITやプログラミングに関するニュース

ブログに戻る

コメントを残す

コメントは公開前に承認される必要があることにご注意ください。

企業・法人向けのIT・プログラミング・生成AI研修を探す、比較する - IT・プログラミングを知って学べるコネクトメディア CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプが提供する無料で学べるプログラミングスクール講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア 3.5日の研修で、年間1,600時間の削減効果が見込まれる。東京きらぼしフィナンシャルグループのDX人材育成事例 - IT・プログラミングを知って学べるコネクトメディア 配属3ヶ月で30%の生産性向上を実現するいよぎんコンピュータサービスの新人研修に迫る - IT・プログラミングを知って学べるコネクトメディア 金融業界の業務効率化を加速するニッセイアセットマネジメントの生成AI×GAS活用研修事例 - IT・プログラミングを知って学べるコネクトメディア 【製造業のDX人材育成事例】デジタル人材の即戦力化を実現する、日本ガイシ株式会社の異動者向オンボーディング研修 - ITやプログラミングを知って学べるコネクトメディア フューチャーアーキテクト株式会社が実現した新入社員向けIT研修プログラムでタスクフォース制度が主体的な学びと成長を生み出す - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【IT新入社員研修】オンラインとオフラインの最適バランスを実現したFutureOneの導入事例 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【新入社員研修】柔軟なハイブリッド型Java研修で実現した新卒20名の成長と成果|サークレイス株式会社 - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/現場により近いところにデジタルを根付かせるDX基礎講座研修|株式会社ブリヂストン - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/業務の効率化・DX推進に向けたIT人材育成への第一歩|株式会社カナエ - ITやプログラミングを知って学べるコネクトメディア 企業・法人向けのIT・プログラミング研修 - ITやプログラミングを知って学べるコネクトメディア

新着記事

対象者別で探す

子供(小学生・中学生・高校生)向け
プログラミング教室検索する

子供(小学生・中学生・高校生)がロボットやプログラミング言語を学ぶことができるオフラインからオンラインスクールを検索、比較することが可能です。

子供(小学生・中学生・高校生)
プログラミング教室検索する

ITやプログラムなどの
最新情報を検索する

日々、新しいITやプログラミング言語の情報が流れていきますが、特定の情報を時系列でニュースやコラムを確認することができます。

ITやプログラムなどの
最新情報を検索する