2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonでファイルを整理する

Last updated at Posted at 2023-04-16

作りたいもの

ドキュメントフォルダに大量のファイルが溜まってしまったため、次の機能を持ったプログラムを作成することにしました。

  • 仕分け元フォルダ内(サブフォルダを含む)のファイルを更新日時に基づいて、別フォルダに整理する。
  • 仕分け先には更新年月ごとのサブフォルダを作成し、ファイルはその中にコピーする。
  • 重複するファイル(MD5ハッシュ値が同一のもの)は、ファイル名を変更して保存する。

Pythonコード

1.モジュールのインポートとロケールの設定

import os
import shutil
from datetime import datetime
import locale
import hashlib
from tkinter import Tk, filedialog

# ロケールを設定
locale.setlocale(locale.LC_ALL, 'ja_JP.UTF-8')
  • shutilは、タイムスタンプの情報も含めてファイルをコピーするために使用しています。
  • localeは、処理全体のロケールを日本語に設定するために使用しています。
  • hashlibは、MD5ハッシュ値でファイルを比較するために使用しています。
  • tkinterは、仕分け元、仕分け先フォルダをGUIで指定するために使用しています。

デフォルトでは英語に従って日付や時刻がフォーマットされるため、処理全体のロケールを日本語にしています。この部分は省略可能です。

2.ルートウィンドウの作成と非表示

# ルートウィンドウを非表示にする
root = Tk()
root.withdraw()

Tkinterを使ってダイアログボックスを表示するために、ルートウィンドウを作成して非表示にしています。

3.ダイアログボックスで仕分け元・先のフォルダを選択

# 仕分け元のフォルダをダイアログで選択する
src_folder = filedialog.askdirectory(title="仕分け元のフォルダを選択してください")

# 仕分け先のフォルダをダイアログで選択する
dst_folder = filedialog.askdirectory(title="仕分け先のフォルダを選択してください")

コードを実行すると、ダイアログが2回表示されます。1回目では仕分け元フォルダを、2回目は仕分け先フォルダを選択してください。

4.日付フォーマットの設定

# 仕分ける際のファイルの更新日時のフォーマット
date_format = "%Y-%m-%d %H:%M:%S.%f"

ファイルの更新日時を処理するためのフォーマットを設定しています。

5.仕分け処理

# 仕分けるフォルダ内のファイルを取得
for root, dirs, files in os.walk(src_folder):
    for file in files:
        # ファイルのパス
        file_path = os.path.join(root, file)
        # MD5ハッシュ値を取得
        with open(file_path, 'rb') as f:
            file_data = f.read()
        file_hash = hashlib.md5(file_data).hexdigest()
        # 仕分け先のフォルダパスを生成
        mtime = os.path.getmtime(file_path)
        mtime_obj = datetime.fromtimestamp(mtime)
        year_month_str = mtime_obj.strftime("%Y年%m月")
        dst_path = os.path.join(dst_folder, year_month_str)
        # 仕分け先のフォルダが存在しなければ作成
        os.makedirs(dst_path, exist_ok=True)
        # 仕分け先に同じハッシュ値のファイルが存在する場合は、ファイル名を変更してコピーする
        dst_file_path = os.path.join(dst_path, file)
        i = 2
        while os.path.exists(dst_file_path):
            new_file_name = os.path.splitext(file)[0] + f" _重複{i}" + os.path.splitext(file)[1]
            dst_file_path = os.path.join(dst_path, new_file_name)
            i += 1
        # ファイルをコピーする
        shutil.copy2(file_path, dst_file_path)

1.os.walk() を使って、仕分け元のフォルダ内のすべてのファイルを取得します。
2.各ファイルについて以下の処理を行います。

  • ファイルのパスを取得します。
  • ファイルのMD5ハッシュ値を計算します。これは、後で重複ファイルを確認する際に使用します。
  • ファイルの更新日時(mtime)を取得し、年と月に基づいて仕分け先のフォルダパスを生成します。
  • 仕分け先のフォルダが存在しない場合は、新しく作成します。
  • 仕分け先に同じハッシュ値のファイルが存在する場合、ファイル名を変更してコピーします。これは、重複するファイルが上書きされないようにするためです。
  • 最後にファイルをコピーします。

この処理で、仕分け元のフォルダ内のファイルが、仕分け先のフォルダに更新日時に基づいて整理されます。具体的には、ファイルが更新された年と月に基づいて、仕分け先のフォルダ内にサブフォルダを作成し、ファイルを移動します。例えば、2022年9月に更新されたファイルは、仕分け先フォルダ内の「2022年09月」という名前のサブフォルダに移動されます。

また、重複したファイルの上書きを防ぎ、すべてのファイルを保持するため、ファイル名を変更して保存しています(重複ファイルが見つかった場合、ファイル名に、"_重複" という接尾辞と連番を追加しています)。

6.メモ

  • このコードを書く時間を使って手動でファイルを整理すれば良かった。
  • そもそも少しずつファイルを整理しておけば良かった。
  • Pythonのコードを書くのが1年以上ぶりとなったため、一部のモジュールを使った処理についてChatGPT-4に助けてもらいました。便利な世の中になったものです。

以下、連結したコードです。

Python filesorter.py
import os
import shutil
from datetime import datetime
import locale
import hashlib
from tkinter import Tk, filedialog

# ロケールを設定
locale.setlocale(locale.LC_ALL, 'ja_JP.UTF-8')

# ルートウィンドウを非表示にする
root = Tk()
root.withdraw()

# 仕分け元のフォルダをダイアログで選択する
src_folder = filedialog.askdirectory(title="仕分け元のフォルダを選択してください")

# 仕分け先のフォルダをダイアログで選択する
dst_folder = filedialog.askdirectory(title="仕分け先のフォルダを選択してください")

# 仕分ける際のファイルの更新日時のフォーマット
date_format = "%Y-%m-%d %H:%M:%S.%f"

# 仕分けるフォルダ内のファイルを取得
for root, dirs, files in os.walk(src_folder):
    for file in files:
        # ファイルのパス
        file_path = os.path.join(root, file)
        # MD5ハッシュ値を取得
        with open(file_path, 'rb') as f:
            file_data = f.read()
        file_hash = hashlib.md5(file_data).hexdigest()
        # 仕分け先のフォルダパスを生成
        mtime = os.path.getmtime(file_path)
        mtime_obj = datetime.fromtimestamp(mtime)
        year_month_str = mtime_obj.strftime("%Y年%m月")
        dst_path = os.path.join(dst_folder, year_month_str)
        # 仕分け先のフォルダが存在しなければ作成
        os.makedirs(dst_path, exist_ok=True)
        # 仕分け先に同じハッシュ値のファイルが存在する場合は、ファイル名を変更してコピーする
        dst_file_path = os.path.join(dst_path, file)
        i = 2
        while os.path.exists(dst_file_path):
            new_file_name = os.path.splitext(file)[0] + f" _重複{i}" + os.path.splitext(file)[1]
            dst_file_path = os.path.join(dst_path, new_file_name)
            i += 1
        # ファイルをコピーする
        shutil.copy2(file_path, dst_file_path)
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?