MENU

Pythonでファイル名を一括変更|商品画像と試運転

当ページのリンクには広告(PR)が含まれていることがあります。
フォルダ内のファイル名を一括整理するPythonツールのアイキャッチ
お悩み女子

商品画像の名前が連番のままで、どの商品か探せません。一括で変える前に、間違いを確認したいです。

Pythonでファイル名を一括変更するときは、変更予定を表示してから、コピーした画像だけに適用する形にすると確認しやすくなります。商品コードと元のファイル名をCSVで対応させれば、名前に商品情報がない画像も整理できます。

名前のルールを決め、試運転・重複チェック・変更記録まで順に進めます。Windows 11とPython 3.12.10で、使い捨てのファイルを使ってコードを確認しています。実際の商品画像や業務フォルダでは実行していません。

この記事でわかること
  • 対象フォルダと名前のルールの決め方
  • 対応表CSVから商品コードと連番を付ける方法
  • 変更しない試運転と、衝突したときの停止
  • 変更記録を使った確認と復元の考え方
目次

Pythonでファイル名を一括変更する前に決める3項目

ファイル名は表計算ソフトの参照やWebページから使われていることがあります。対象、付け方、戻し方を決めてからコードに進みます。

対象のコピー

元フォルダをコピーし、練習用画像という専用フォルダを用意します。以下のツールはその直下のファイルだけを対象にし、下の階層はたどりません。途中でファイルが増減しない場所を選びます。

例のファイルはIMG_4821.JPG、IMG_4822.JPG、IMG_4830.PNGの3つです。画像の内容は変更しませんが、ファイル名を変えると参照先も変わるため、WordPressにアップロード済みの画像や同期中の共有フォルダを直接指定しないでください。

新しい名前の規則

完成形はimg_A001_01.jpgのように接頭辞・商品コード・商品内の連番・拡張子を組み合わせます。img_を付けるのは、CONなどWindowsで特別な意味を持つ名前をそのまま使わないためです。商品コードは半角英数字と_、-だけに限定します。

並び順にも意味があります。今回は対応表CSVの行順に番号を振ります。写真を撮った順や更新日時の順ではありません。1枚目を正面写真にしたい場合は、CSV上で正面写真を先に並べます。

変更前後の記録

変える前の一覧だけでは途中で止まったときに何件終わったか分かりません。1件変更するたびに記録を書き、変更前と変更後の絶対パスを残します。記録自体が元ファイルのコピーになるわけではないため、元フォルダのコピーも残します。

Pythonでファイル名を一括変更|対応表CSVの準備

商品画像の整理では、元の名前だけから商品コードを推測しないほうが確実です。人が確認した対応表を入力に使います。

次をmapping.csvとしてUTF-8で保存します。見出しは元の名前、商品コードの2列です。同じ商品コードを複数行に書くと、その商品内で01、02と連番が増えます。

元の名前,商品コード
IMG_4821.JPG,A001
IMG_4822.JPG,A001
IMG_4830.PNG,B014

元の名前は拡張子まで含めて一致させます。A001は文字列として扱うため、先頭の文字やゼロが残ります。Excelで対応表を作るときは、商品コード列を文字列にしてから入力すると、意図しない数値化を防ぎやすくなります。

対応表に書いていないファイルは処理しません。一方、対応表に書いたファイルが見つからない場合は変更する前に停止します。対象外を黙って飛ばすと、入力ミスと意図的な除外の区別がつかなくなるためです。

Pythonでファイル名を一括変更|試運転から始めるコード

次のプログラムをrename_images.pyで保存します。追加ライブラリは使わず、Pythonに入っている機能だけで動きます。

変更の予定をすべて作ってから、変更元・変更先の重複と既存ファイルを確認します。大文字と小文字の違いだけで別ファイルと判断しないよう、元の名前と変更先の比較にはcasefold()を使っています。

import argparse
import csv
import re
from pathlib import Path

parser = argparse.ArgumentParser(description="商品画像の名前を整理")
parser.add_argument("folder", type=Path)
parser.add_argument("mapping", type=Path)
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
folder = args.folder.resolve(strict=True)
with args.mapping.open(encoding="utf-8-sig", newline="") as f:
    rows = list(csv.DictReader(f))
existing = {p.name.casefold() for p in folder.iterdir()}
counts, seen, sources, plan = {}, set(), set(), []
for row in rows:
    name, product = row["元の名前"], row["商品コード"].strip()
    source_key = name.casefold()
    if Path(name).name != name or source_key in sources:
        raise ValueError("元の名前は重複のないファイル名にします")
    sources.add(source_key)
    src = folder / name
    if src.is_symlink() or not src.is_file():
        raise ValueError(f"対象ファイルがありません: {name}")
    if not re.fullmatch(r"[A-Za-z0-9_-]+", product):
        raise ValueError("商品コードは半角英数字・_・-で指定します")
    if src.suffix.lower() not in {".jpg", ".jpeg", ".png"}:
        raise ValueError(f"対象外の拡張子です: {name}")
    counts[product] = counts.get(product, 0) + 1
    dst = src.with_name(f"img_{product}_{counts[product]:02d}{src.suffix.lower()}")
    key = dst.name.casefold()
    if key in seen or key in existing:
        raise ValueError(f"変更後の名前が重なります: {dst.name}")
    seen.add(key)
    plan.append((src, dst))
for src, dst in plan:
    print(f"{src.name} -> {dst.name}")
print(f"対象: {len(plan)}件")
if not args.apply:
    print("試運転: ファイル名は変更していません")
else:
    # 同名の記録を上書きしない。記録は対象フォルダの外へ。
    with Path("rename_log.csv").open("x", encoding="utf-8-sig", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(["変更前", "変更後"])
        for src, dst in plan:
            src.rename(dst)
            writer.writerow([str(src), str(dst)])
            f.flush()
    print("変更済み: rename_log.csv に記録しました")

通常は表示だけで終了します。–applyを付けた場合だけ名前を変えます。rename_log.csvはコマンドを実行した場所に新規作成し、同じ名前の記録があれば止まります。ツールと記録は練習用画像フォルダの外に置いてください。

これは、他のプログラムが同時にファイルを作らないローカル作業向けの例です。確認後から変更までの間に対象が変わると失敗することがあります。共有フォルダでの同時実行や、名前の入れ替えには対応していません。

Pythonでファイル名を一括変更|結果の確認と停止時の対応

まず試運転で表示を見て、商品コードと順番が対応表どおりか確認します。問題がない場合だけ、コピー上で変更します。

試運転と適用の結果

py -3.12 rename_images.py "練習用画像" mapping.csv
IMG_4821.JPG -> img_A001_01.jpg
IMG_4822.JPG -> img_A001_02.jpg
IMG_4830.PNG -> img_B014_01.png
対象: 3件
試運転: ファイル名は変更していません

この試運転の前後で、3ファイルの名前が変わらないことを確認しました。表示が想定どおりなら、同じコマンドの末尾に–applyを付けます。名前を変えた直後には、画像を開けることと記録の3行を見直します。

py -3.12 rename_images.py "練習用画像" mapping.csv --apply
IMG_4821.JPG -> img_A001_01.jpg
IMG_4822.JPG -> img_A001_02.jpg
IMG_4830.PNG -> img_B014_01.png
対象: 3件
変更済み: rename_log.csv に記録しました

一度変更した後は、元の名前が見つからなくなるため、同じ対応表で繰り返し実行しません。追加の画像を処理するときも、別のコピーと新しい対応表を作って確認するほうが、どこまで変更したかを追いやすくなります。

名前が重なる場合

練習用フォルダにimg_A001_01.jpgを先に置くと、変更後の名前が重なりますというエラーで停止しました。元の名前が異なっていても、変更先が同じなら処理を進めません。

対応表の元の名前にIMG_4821.JPGとimg_4821.jpgを並べた場合も、同じ元ファイルの重複として変更前に停止します。Windowsの使い捨てファイルで、名前が変わらず、変更記録も作られないことを確認しています。

WindowsのPath.rename()は、変更先が存在するとFileExistsErrorになります。Path.replace()は置き換える動作なので、同じつもりで差し替えないでください。商品コードに/や?がある場合も、このコードでは名前を作る前に止めます。

途中停止と戻し方

PermissionErrorが出た場合は、ファイルを開いているアプリやアクセス権を確認します。止まった後に–applyを繰り返す前に、rename_log.csvと現在のフォルダを照合してください。記録がある行は、その行の変更後の名前が実在するかを見ます。

戻す場合は、新しい変更から逆順に、変更後を変更前へ戻します。元の名前が既に使われていたり、変更後に別の作業をしたりしていれば自動復元は危険です。最初のコピーからやり直す方法が取れるよう、確認が終わるまでコピーを保持します。

なべくん

先に一覧を見て、商品コードと写真の順番を確かめましょう。名前を変える処理より、対象を間違えない準備が大切です。

Pythonのファイル名一括変更|よくある質問

実行前に迷いやすい点を確認します。

画像の形式もJPGからPNGに変わりますか?

変わりません。名前と画像形式は別です。拡張子を小文字にそろえるだけで、画像データの変換は行いません。画像を変換したい場合は別の処理として扱います。

フォルダ内の全ファイルを連番にできますか?

できますが、どの順に番号を付けるかを先に決めます。ファイル名順、撮影日時順、対応表順では結果が変わります。この例では対応表にある画像だけに、CSVの行順で番号を付けます。

Pythonの一括変更の試運転と記録

まず、変更しない試運転が期待どおりかを確かめます。

この記事のまとめ

対象:元フォルダのコピーを指定する
対応表:商品コードと写真の順番を人が決める
確認:既定は試運転。重複があれば変更前に止める
記録:変更前後を残し、元のコピーも保持する

最初は3枚だけのコピーで、予定の表示と変更後の名前を比べてみてください。

次に進める作業に合わせて、こちらの記事も参考にしてください。

参考資料(2026年10月確認)
pathlib:Path.renameとPath.replace | Python
ファイル名と名前空間 | Microsoft Learn
csv | Python

この記事を書いた人

Watanabeのアバター Watanabe サイト運営者

2020年よりブログ開始。
SEOが思いのほか性にあっていたようで現在に至る。
モットーは「勝率の高い選択をする」
AIは活用するが吉、最後は人間が息を吹き込む。
アートと科学を追求し、日々精進。
―――
収益:6~7桁をウゴウゴ。
サイト:ペラサイト~中規模サイトまで運営中。
案件:1000円以上の案件をメインに取組中。
打ち手:ブラックSEO~ホワイトSEOまで
―――

目次