pythonでフォルダ内のファイルサイズ一覧取得

GUI,python,ファイルサイズ収集,PySimpleGUI,python

フォルダ内のファイルサイズ収集ツールをpythonで作ってみました。

収集した各種情報(階層、種別、パス、ファイル名、作成時刻)は、pandasを使用しエクセルに出力させます。

膨大なファイルの中から、特定のファイルを見つけて何らかの操作(コピー、リネーム、編集等)を行うこともあると思います。

このような複雑な処理を自動化したい場合にも、有用だと思うので興味があれば参考にしてみてください。

はじめに

会社の共有ドライブの容量が満杯になってしまった

当然不要なファイルを見つけて削除、もしくは退避させる必要があるのですが、急ぎでより容量の大きく移動しやすいファイルを探す必要があります。

そんな時いちいちフォルダを一つずつ右クリックしてプロパティからサイズを抽出なんてやってられないですよね。

コマンドプロンプトでまとめて出力できますが、ツールで誰でも手軽に確認が出来ればいいなと思い作ってみました。

検討

とりあえず以下機能はほしいかな。

・excelで出力

・GUIで各種設定可能

・ベースのフォルダパス指定

・フォルダの階層指定

・フォルダ内のファイル情報抽出有無指定

実装

今回は再起処理にチャレンジしてみました。

普段業務の組み込みソフトには、そんな実装許されてないのでいい気分転換になりました。

ソース

get_dir_size_subが再起関数となっており、ディレクトリを見つけるたびに内部の情報を検索します。

戻り値にファイルサイズを渡すことで、最終的にtotalのフォルダサイズを上位へ伝えることが可能。

# coding: utf -8
import PySimpleGUI as sg
from tkinter import filedialog
import os
import pathlib
import datetime
import pprint
import openpyxl

# テーマの設定
sg.theme("SystemDefault ")

L = [
    [sg.Text("階層", size=(5,1)) , sg.InputText(default_text="1" ,    size=(5,1) ,    key="-DIRECTORY_LEVEL-")],
    [sg.Radio(text='フォルダ内のファイル情報抽出 有', default=True,         size=(27,1) ,    key="-FILE_CHECK_VALID-" ,    group_id='FILE_CHECK')],
    [sg.Radio(text='フォルダ内のファイル情報抽出 無',                       size=(27,1) ,    key="-FILE_CHECK_INVALID-" ,    group_id='FILE_CHECK')],
    [sg.Button("開始", border_width=4 ,                                  size =(28,1),    key="-BTN_START-")],
]

# 出力管理情報
g_file_inf = []

def main():
    # ウィンドウ作成
    window = sg.Window ("フォルダ情報収集", L)
    # イベントループ
    while True:
        # イベントの読み取り(イベント待ち)
        event , values = window.read()
        if event == "-BTN_START-":
            get_dir_size(int(values["-DIRECTORY_LEVEL-"]),values["-FILE_CHECK_VALID-"])
            mk_excel()
            break
        elif event == None:
            print(" 終了します. ")
            break
    # 終了処理
    window.close()


def get_dir_size(count,flile_chk_flg):
    # 親フォルダの情報格納領域を予約
    file_inf = {}
    g_file_inf.append(file_inf)
    # 対象のフォルダパス取得
    folder_path = filedialog.askdirectory()
    total = get_dir_size_sub(folder_path,count,count,flile_chk_flg)
    # 親フォルダの情報格納
    p = pathlib.Path(folder_path)
    g_file_inf[0]["階層"] = 0
    file_inf["種別"] = "dir"
    g_file_inf[0]["ファイルパス"] = folder_path
    g_file_inf[0]["ファイル名"] = p.name
    unix_time = p.stat().st_mtime
    date_time = datetime.datetime.fromtimestamp(unix_time)
    date_time = date_time.strftime('%Y/%m/%d %H:%M:%S')
    g_file_inf[0]["作成時刻"] = date_time
    g_file_inf[0]["サイズ"] = total
    pprint.pprint(g_file_inf)


def get_dir_size_sub(path,count,count_max,flile_chk_flg):
    total = 0
    with os.scandir(path) as it:
        for entry in it:
            file_inf = {}
            # 階層が指定値以内の場合、情報取得
            if 0 < count:
                file_inf["階層"] = count_max - count + 1
                file_inf["ファイルパス"] = entry.path
                file_inf["ファイル名"] = entry.name
                # 時刻情報取得
                unix_time = entry.stat().st_mtime
                date_time = datetime.datetime.fromtimestamp(unix_time)
                date_time = date_time.strftime('%Y/%m/%d %H:%M:%S')
                file_inf["作成時刻"] = date_time
                # 対象ファイルがディレクトリ
                if entry.is_dir():
                    file_inf["種別"] = "dir"
                    # 事前にディレクトリ情報格納領域取得
                    row_cnt = 0
                    g_file_inf.append(file_inf)
                    row_cnt = len(g_file_inf)-1
                    # 再起処理にてディレクトリ内の情報取得、ディレクトリのサイズ取得
                    dir_size = get_dir_size_sub(entry.path,count-1,count_max,flile_chk_flg)
                    # ディレクトリのサイズ反映
                    total += dir_size
                    g_file_inf[row_cnt]["サイズ"] = dir_size
                # 対象ファイルがディレクトリ以外
                elif entry.is_file():
                    total += entry.stat().st_size
                    if True == flile_chk_flg:
                        file_inf["種別"] = "file"
                        file_inf["サイズ"] = entry.stat().st_size
                        g_file_inf.append(file_inf)
            # 階層が指定値以内の場合、サイズだけ取得
            else:
                if entry.is_file():
                    total += entry.stat().st_size
                elif entry.is_dir():
                    total += get_dir_size_sub(entry.path,count-1,count_max,flile_chk_flg)
    return total


def mk_excel():
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = '出力結果'
    # ヘッダ
    ws.cell(row=1,column=1).value = "階層"
    ws.cell(row=1,column=2).value = "種別"
    ws.cell(row=1,column=3).value = "ファイルパス"
    ws.cell(row=1,column=4).value = "ファイル名"
    ws.cell(row=1,column=5).value = "サイズ(bytes)"
    ws.cell(row=1,column=6).value = "作成時刻"
    # 取得情報反映
    for i, file_inf in enumerate(g_file_inf):
        ws.cell(row=i+2,column=1).value = file_inf["階層"]
        ws.cell(row=i+2,column=2).value = file_inf["種別"]
        ws.cell(row=i+2,column=3).value = file_inf["ファイルパス"]
        ws.cell(row=i+2,column=4).value = file_inf["ファイル名"]
        ws.cell(row=i+2,column=5).value = file_inf["サイズ"]
        ws.cell(row=i+2,column=6).value = file_inf["作成時刻"]
    # 列幅調整
    for col in ws.columns:
        max_length = 0
        for cell in col:
            if len(str(cell.value)) > max_length:
                max_length = len(str(cell.value))
        adjusted_width = (max_length + 2)
        ws.column_dimensions[col[0].column_letter].width = adjusted_width
    # 保存
    now = datetime.datetime.now()
    file_name = 'ファイル一覧_{}.xlsx'.format(now.strftime('%Y%m%d_%H%M%S'))
    wb.save(file_name)

    return


if __name__ == '__main__':

    main()

GUI

PySimpleGUIライブラリで簡単なGUIを表示させました。

階層によって出力するファイルのネストを指定できます。

また、ディレクトリのサイズだけで十分な場合は下のラジオボタンを無にします。

開始ボタンを押すとフォルダ指定画面が出るので、対象のフォルダを指定すると収集結果をエクセルに出力します。

出力結果

ソースファイルと同じフォルダへ、出力時間をつけて出力。

列幅調整の処理も入れているので、ある程度見やすく出力してくれるようにはなっています。

最後に

単純なサイズ確認であれば、わざわざpython使わなくとも以下ツールで十分だと思います。

とても使いやすいのでおすすめです。