🎉

フォルダ・ファイルの変更をざっとみたいときに

2023/09/27に公開

私はITに強い税理士・公認会計士の小松啓です。今日はコードでどのように業務を自動化しているかをご紹介します。

特に財務デューデリジェンスでは、多くのデータがクラウドにアップロードされます。その管理が大変です。そこで、毎朝ローカルに新しいフォルダをダウンロードし、Pythonスクリプトで更新されたファイルを特定します。これでデータの整理が効率的に行えます。

このスクリプトはフォルダとファイルの構造をテキストファイルで見られるようにします。テキストファイルには年月日が付き、指定の場所に保存されます。

import os
from tkinter import Tk, filedialog, simpledialog
from datetime import datetime


def list_files(startpath):
    paths_list = []
    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, "").count(os.sep)
        indent = " " * 4 * (level)
        paths_list.append("{}{}/".format(indent, os.path.basename(root)))
        subindent = " " * 4 * (level + 1)
        for f in files:
            paths_list.append("{}{}".format(subindent, f))
    return paths_list


def main(output_directory):
    root = Tk()
    root.withdraw()
    directory_path = filedialog.askdirectory(title="どのディレクトリ構造を可視化するのか選択してください")
    file_list = list_files(directory_path)

    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    output_path = os.path.join(
        output_directory, "file_structure_{}.txt".format(timestamp)
    )

    with open(output_path, "w", encoding="utf-8") as f:
        for item in file_list:
            f.write("%s\n" % item)

    simpledialog.messagebox.showinfo(
        "情報", "file_structure_{}.txtとして保存しました。".format(timestamp)
    )


if __name__ == "__main__":
    output_dir = input("出力パスを入力してください: ")
    main(output_dir)

こんな感じのテキストファイルを出力できます。

test_directory/
    file1.txt
    file2.txt
    sub_directory/
        file3.txt
        file4.txt
        sub_sub_directory/
            file5.txt
            file6.txt

file_structure_20230927132459.txt こんな感じで年月日の情報がついたテキストファイルが任意のディレクトリに保存されます。

翌日、新たなデータがクラウドに共有された場合、そのフォルダをダウンロードし、名前を変更して次のPythonスクリプトを実行します。

import os
from tkinter import Tk, filedialog
from datetime import datetime


def list_files(startpath):
    paths_list = []
    raw_paths = []
    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, "").count(os.sep)
        indent = " " * 4 * (level)
        folder_name = os.path.basename(root)
        paths_list.append(f"{indent}{folder_name}/")
        raw_paths.append(f"{folder_name}/")

        subindent = " " * 4 * (level + 1)
        for f in files:
            paths_list.append(f"{subindent}{f}")
            raw_paths.append(f)
    return paths_list, raw_paths


def read_old_file(old_file_path):
    if os.path.exists(old_file_path):
        with open(old_file_path, "r", encoding="utf-8") as f:
            return [x.strip() for x in f.readlines()]
    else:
        return []


def main(output_directory):
    root = Tk()
    root.withdraw()

    directory_path = filedialog.askdirectory(title="どのディレクトリ構造を可視化するか選択してください")
    after_info = os.path.basename(directory_path)

    new_file_list, new_raw_list = list_files(directory_path)

    old_file_path = filedialog.askopenfilename(title="比較する古いテキストファイルを選択してください")
    before_info = os.path.basename(old_file_path)

    old_file_list = read_old_file(old_file_path)

    diff_added = set(new_raw_list) - set(old_file_list)
    diff_removed = set(old_file_list) - set(new_raw_list)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M_%S")
    plain_output_path = os.path.join(
        output_directory, f"file_structure_{timestamp}_plain.txt"
    )
    diff_output_path = os.path.join(
        output_directory, f"file_structure_{timestamp}_diff.txt"
    )

    # 差分情報なしのプレーンなテキストファイル
    with open(plain_output_path, "w", encoding="utf-8") as f:
        f.write(f"Before: {before_info}\n")
        f.write(f"After: {after_info}\n\n")
        for line in new_file_list:
            f.write(f"{line}\n")

    # 差分情報が含まれたテキストファイル
    with open(diff_output_path, "w", encoding="utf-8") as f:
        f.write(f"Before: {before_info}\n")
        f.write(f"After: {after_info}\n\n")
        for i, line in enumerate(new_file_list):
            prefix = "+ " if new_raw_list[i] in diff_added else ""
            f.write(f"{prefix}{line}\n")

        for line in diff_removed:
            indentation = " " * 4 * (line.count("/") - 1)
            f.write(f"{indentation}- {line}\n")


if __name__ == "__main__":
    output_dir = input("出力パスを入力してください: ")
    main(output_dir)

これを実行すると次のような2つのファイルができます

file_structure_20230927_1328_14_diff.txt

Before: file_structure_20230927132459.txt
After: test_directory

test_directory/
    file1.txt
    file2.txt
    sub_directory/
        file3.txt
        file4.txt
        sub_sub_directory/
            file5.txt
+             file6 - コピー (2).txt
+             file6 - コピー (3).txt
+             file6 - コピー (4).txt
+             file6 - コピー.txt
            file6.txt

file_structure_20230927_1328_14_plain.txt

Before: file_structure_20230927132459.txt
After: test_directory

test_directory/
    file1.txt
    file2.txt
    sub_directory/
        file3.txt
        file4.txt
        sub_sub_directory/
            file5.txt
            file6 - コピー (2).txt
            file6 - コピー (3).txt
            file6 - コピー (4).txt
            file6 - コピー.txt
            file6.txt

_diffとついた方は、差分後を管理しているテキストファイルです。
_plainとついた方は、後日差分を比較するための元になるテキストファイルです。

Pythonスクリプトを一日に一度実行するだけで、新しく追加されたクラウドのデータがすぐに分かります。

とても便利な世の中です。

税理士事務所としてはITエンジニアの方IT業の方を積極的に支援しています。itにめっぽう強い税理士としてクラウドのサービスはもちろん非同期的なコミュニケーションによる即レス、ストレスフリーなバックオフィス環境をご提供しています。

是非ご一報ください。
https://twitter.com/EUREKAPU_com
Web
https://tax.eurekapu.com/tax/

Discussion