てんこ製作

Tenco Works

フォルダの利用量一覧をpythonで表示する

会社でネットワーク上のフォルダのデータ量が偉いことになってるっていうので、どのくらいになってるか調べる必要が出てきました。

最初はPower Shellでやってたんですが、ネットワークの性能があまり良くないせいか業務中に調べきることができなかったので、今度はお試しにpythonでやってみようと思った次第。pythonでフォルダ毎にどのくらいの容量を食っているかを調べる方法は、ネットで検索すればいろいろ出てきます。

完成したプログラム

import os
import pathlib
import sys

def main(args):
    #root_path = r"\\ServerName\SharedFolder"
    root_path = args[1]
    f_size = get_dir_size(pathlib.Path(root_path))
    print(args[1]+"\t"+str(f_size))


def get_dir_size(afile):
    flist = list(afile.glob(r"*"))
    total_size = 0
    for afile in flist:
        # ファイルだったら
        if afile.is_file():
            total_size = total_size + afile.stat().st_size
        # ディレクトリだったら
        elif afile.is_dir():
            d_size = get_dir_size(afile)
            total_size = total_size + d_size
            print(str(afile) + "\t" + str(d_size))
    return total_size


if __name__ == '__main__':
    main(sys.argv)

考え方

フォルダのようなツリーを探索するには再帰関数を使うのがてんこ的にはテッパンかなと思ってますので、今回も再帰関数でやってみます。pythonで再帰関数はパフォーマンス良くないらしいですが・・・。スピードは別途会社に持ってって調べてみます。

まず1個分のフォルダの容量を調べる手順としては、

  1. フォルダ直下のファイル・フォルダを取得する。
  2. ファイルだったら、そのファイルのサイズを足し込んでいく。
  3. フォルダだったらそのフォルダ配下の容量を足し込んでいく。
  4. 上で出した2.と3.の合計がフォルダの使用量になる。

という感じになります。

ここでポイントは3.の手順の内容。そのフォルダ配下の容量を調べるにはどうするかというと、

  1. フォルダ直下のファイル・フォルダを取得する。
  2. ファイルだったら、そのファイルのサイズを足し込んでいく。
  3. フォルダだったらそのフォルダ配下の容量を足し込んでいく。
  4. 上で出した2.と3.の合計がフォルダの使用量になる。

となります。最初の手順と全く一緒です。さらにその配下にフォルダが存在しても同様にその配下を調べる・・・ということを階層分だけ繰り返していきます。

これをプログラムで書くときはどうするか?

上の1.〜4.の手順を含む関数を一個作って、手順3.の部分に当たるところには自分自身(関数)を呼び出すようにすればいいです。これが再帰処理(再帰関数)というわけです。

プログラム説明

メインになるところ

def main(args):
    #root_path = r"\\ServerName\SharedFolder"
    root_path = args[1]
    f_size = get_dir_size(pathlib.Path(root_path))
    print(args[1]+"\t"+str(f_size))


if __name__ == '__main__':
    main(sys.argv)

main()関数を作っておいて、これが最初に実行されるように書きました。この書き方は必須ではないですが、てんこの好みでこうしてます。

main()関数でやっていることは、プログラム起動時のコマンドライン引数args[1](元はsys.argv[1])をpathlibに入れて(pathlib.Path(args[1]))、get_dir_size()という関数を呼び出しているだけです。

get_dir_size()関数はこの後自分で書く関数で、こいつが再帰関数になります。

再帰関数の部分

def get_dir_size(afile):
    flist = list(afile.glob(r"*"))
    total_size = 0
    for afile in flist:
        # ファイルだったら
        if afile.is_file():
            total_size = total_size + afile.stat().st_size
        # ディレクトリだったら
        elif afile.is_dir():
            d_size = get_dir_size(afile)
            total_size = total_size + d_size
            print(str(afile) + "\t" + str(d_size))
    return total_size

get_dir_size()関数が再帰関数になります。

まず、pathlibglob()メソッドを使って、指定されたパス配下のファイル・フォルダ一覧を取得します。

あと、合計サイズを入れておく用の変数total_sizeを0で初期化しておきます。

取得した一覧の中身はfor文で処理します。中身はファイルかフォルダのどちらかだと思うので、ファイルだったらファイルサイズを調べてtotal_sizeに足しこみます。フォルダだったらその配下のサイズを調べるためにget_dir_size()を呼び出して、返ってきた値をtotal_sizeに足しこみます。

そしてget_dir_size()を呼び出してくれた元に調べた結果を返すため、return total_sizeとしています。

実は・・・

pathlibのglob()メソッドでも配下のパスをすべて一気に撮ってきてくれる機能があるのでそれを使っても同じ結果は得られると思います。

今回はディレクトリごとにも容量を調べていきたいということもあって、glob()の方は使わず自分で再帰関数を書く形にしました。その辺は臨機応変になると思います。