Pythonでファイル名の一括変換スクリプトを書いてみる


きっかけ

突然ですが、みなさんは写真を撮られますか?
私は、i-Phoneで料理や風景を記念に撮ることが多いのですが、撮ったら撮りっぱなしで、まめに整理をするわけでもないので、一方的に写真データが増え続けるだけの状況でした。
先日PCのデータ保存用に外付けのHDDを新調したので、これを機にi-Phone内の写真を整理しようと思ったわけです。
ところがいざ写真ファイルを整理し始めてみると、名前が日付+時刻でなんの写真なのかわかりません。
まとめて名前を変えたいなと思ったのが事の始まりでした。

やり方は何個もある

一括変換用のアプリでも入れればよいのですが、調べるのも新たに使用ソフトが増えるのも億劫です。
かといってWindows10のOS機能で名前を変えると「基本のファイル名+(1)」というファイル名が付き、これは何だか嫌でした。
PowerShellやコマンドプロンプトでも同様の処理はできると思いますが、Pythonで遊んでみたかったので作ろうと思った次第です。

書く前の整理

まずは、Pythonに何をやらせたいのかを整理します。
やりたいことは「任意のフォルダ配下の画像ファイルの名前を一括変換する」ことです。
実際には以下の2つの処理を順番に実施します。

処理の内容

①:任意のフォルダ配下にある画像ファイルの一覧を取得する
②:取得したファイル一覧の名前を命名規則に則って変換する

使用できるライブラリ(モジュール)の確認

やることが決まったので、どうやったらできるかを調べます。
具体的にはPythonで「①:ファイルの一覧取得をする方法」と「②:名前の変更をする方法」を調べます。
ググれば簡単に見つかりました。

①:ファイルの一覧を取得する

最初に見つけたのは、標準ライブラリに含まれる「os」モジュールの「listdir」関数です。
以下のようなことができるとのことで、機能としては十分です。

listdir関数
・ファイル名とフォルダ名の両方の一覧を取得
・ファイル名のみの一覧を取得
・フォルダ名のみの一覧を取得

しかし、ここで問題が発生しました。画像ファイルの名前の一覧を取得したいので、jpgやpngといった拡張子のものだけを取得したいのですが、特殊文字の*(ワイルドカード)が使えないというのです。

そこで見つけたのが「os」モジュールの「glob」関数でした。
*(ワイルドカード)の使用や再帰的な処理(今回は不要ですが)が可能とのことです。

②:ファイル名を変更する

ファイル名を変更する方法もすぐに見つかりました。
「os」モジュール中の「rename」関数です。

書いてみる

使用環境は下記となります。
関数も見つかったので、早速書いてみます。

OS:Windows10 Pro 2004
Python:3.7.4

※Python3では明示しない場合は、文字コードが「UTF-8」になる設定とのことですので、
 下記をテキストエディタ等で保存するときは、文字コードを「UTF-8」にしてください。

rename.py
#モジュールのインポート
import os, glob

#ファイル名を取得したいファイルの拡張子を設定
#※ここでは「.jpg」
ext = ".jpg"

#ファイル名の一覧取得
#ここではrename.pyと同フォルダ内にある.jpgファイルを取得しています。
files = glob.glob("*" + ext)

#名前に使用する数値のカウンタを初期化
i = 1

#ファイル名の一覧に対して以下を繰り返し実施
#ファイル名一覧から1つを取り出して、変数「old_name」に格納する
for old_name in files:

    #変更後の名前のベースを設定
    #※ここでは「テスト_001」から数値が+1されていくように設定しています
    change_name = "テスト_" + "{0:03d}".format(i)

    #変更後の名称を変数「new_name」に格納する
    #※拡張子を後付けしているのは後で変更したくなった時のためです
    new_name = change_name + ext

    #ファイル名の変更
    os.rename(old_name, new_name)

    #新旧ファイル名の対応を表示
    print(old_name + "->" + new_name)

    #名前に使用する数値カウンタをインクリメント
    i += 1

テストしてみる

早速実行してみます。
変更前(1).jpg~変更前(18)がテスト_001.jpg~テスト_018.jpgとなれば成功です。

実行前のスクリーンショット

コマンドプロンプト

実行後のスクリーンショット

無事、一括変更することができましたが、
名前の対応が崩れてしまったようです。。。
※Pythonで変更前のファイル名を名前順でソートすると「コマンドプロンプト」の画像のような順番になるようですね。。。

終わりに

名前の一括変更をPythonで実施してみました。
無事一括変換できましたが、変更前の名前順がおかしいので、対応が変な感じになってしまいました。
今回は対応とれていなくても影響ないのでそのままで、目的は達成できたので満足です。
※対応取りたい場合は、面倒ですがファイル名を別でソートしないとダメですね(1回分解しないとだめかな)。

#2021/03/28 問題の修正完了