フォルダ内のファイルの一覧表を作る

4月から、電子帳票がどうしたこうした、という話があるようです。
会社でも、それに対応した動きがあるようですが、デジタルにシフトするというような大胆な動きはありません。
とりあえずpdfの帳票の一覧表を作って、「ここで管理してますって感じを出す」ということになったようです。
ということで、毎月作成している請求書の一覧表を作ることになりました。
もちろん、帳票を作成はしていますが、わざわざ一覧表なんて作ってないので、システム改修か手で作るかという選択になります。
まぁ、手で作ることになるよね。

やってる感を出すだけなので、請求書を出力したフォルダにcsvファイルを作成して終わりにしようかと考えました。
エクセルで開いてもらえば、表になって見えますからね。

フォルダの構成は、以下のような感じになっています。

\支払い請求書\202201
   \特別\
   \01_スナック1\請求書.pdf
   \02_スナック2\請求書.pdf
   \グループ_山ちゃん\請求書.pdf
   \グループ_山ちゃん\請求明細書.pdf
   \グループ_その他\請求書.pdf
   \居酒屋\101_居酒屋1\請求書.pdf
   \居酒屋\102_居酒屋2\請求書.pdf

ここから、一覧表を作るわけですが、結局はディレクトリの構造そのままなので、ちょいと見栄え良く整える、って感じになります。
あと、「特別」フォルダの下と、「グループ_その他」のデータは必要ありません。

項目は以下にしましたので、ファイルの中を見ないで作成できます。
ファイル名(フォルダ付)、更新日時、送付先、内容
送付先は、フォルダ名の「居酒屋1」のような後ろの部分。
内容は、「請求書」のようにファイル名そのものです。

てな感じで作成したプログラムは、以下になります。

# -*- coding: utf-8 -*-

#Created on Fri Jan 14 10:41:24 2022

#@author: 泥酔

# フォルダ内のファイル名と日付と更新日時から、適当な一覧表を作ってみる
# 必要なのは、フォルダ/ファイル名と宛先と簡単な内容だと思う
# タイムスタンプとは言わないが、ファイル作成時間も記録してみようかと思う
# あくまでファイルの中身ではなく、ファイル情報そのものから作成する

# GUIで行うこと
#  一覧表を作成するフォルダを選択
#  作成ボタンで作業開始
#  終了のポップアップ
# 具体的な作業内容
#  指定されたフォルダ内のPDFファイル情報を集める
#  それをもとにCSVファイルを作成していく
#  項目は、ファイル名、更新日時、送付先、内容
#  (まぁ、ファイル名から判るんだけどね)

import PySimpleGUI as sg
import glob
import os
import datetime

# Windows Layout
layout = [  [sg.In(key='-IN-'),sg.FolderBrowse(target='-IN-',key='folder')],
            [sg.Button('作成',key='go')]  ]

# Make Windows Title=フォルダ内のPDF一覧作成
window = sg.Window('フォルダ内のPDF一覧作成', layout) 

# Main loop
while True:
    event, values = window.read()
    
    print(event, values)
    
    # これがないと無限ループになります
    # プログラムの最後にwindow.close()を書いて終了にする
    if event == sg.WIN_CLOSED: #ウィンドウのXボタンを押したときの処理
        break
    
    # 作成ボタンが押されたら
    if event == 'go':
        # 作業フォルダを定義
        work_folder = values['folder']
        # 表題の文言を作ってからデータ用のリストを用意
        title = '請求書索引簿('+work_folder[-6:-2]+'年'+work_folder[-2:]+'月)'
        data_list = [title,'ファイル名,作成日時,宛先,内容']
        # 1階層目の全pdfファイルをリストにしてソートする
        all_file = glob.glob(work_folder + '/*[_]*/*.pdf')
        all_file.sort()
        # 各ファイルの作成時間を求めてCSV用のデータを作成する
        for dn in all_file:
            # ファイル名から選択フォルダ部分を削除してファイル名を作成
            dfile=dn.replace(work_folder,'')
            # 最終更新日時を取得
            dtime = datetime.datetime.fromtimestamp(os.path.getmtime(dn)).strftime("%Y-%m-%d %H:%M:%S")
            # 宛先を取得
            datesaki = dfile.split('\\')[1].split('_')[1]
            # 内容を取得
            dnaiyou = dfile.split('\\')[2].split('.')[0]
            # その他じゃなければ、出力データに追加
            if datesaki != 'その他':
                data_list.append(dfile+','+dtime+','+datesaki+','+dnaiyou)

        # 2階層目の全pdfファイルをリストにしてソートする
        all_file2 = glob.glob(work_folder + '/居酒屋/*[_]*/*.pdf')
        all_file2.sort()
        # 各ファイルの作成時間を求めてCSV用のデータを作成する
        for dn in all_file2:
            # ファイル名から選択フォルダ部分を削除してファイル名を作成
            dfile=dn.replace(work_folder,'')
            # 最終更新日時を取得
            dtime = datetime.datetime.fromtimestamp(os.path.getmtime(dn)).strftime("%Y-%m-%d %H:%M:%S")
            # 宛先を取得
            datesaki = dfile.split('\\')[1].split('_')[1]
            # 内容を取得
            dnaiyou = dfile.split('\\')[2].split('.')[0]
            # 出力データに追加
            data_list.append(dfile+','+dtime+','+datesaki+','+dnaiyou)
            
        # ファイルを用意
        fout = open(work_folder+'/一覧表.csv','w',encoding='shift_jis')
        for dd in data_list:
            # 見栄えを良くするために\\を/に変換
            dd = dd.replace('\\','/')
            # utf-8からSJISに変換出来ない文字を置き換えておく
            dd = dd.replace(u"\uff3c",u"\u005c")
            dd = dd.replace(u"\uff5e",u"\u301c")
            dd = dd.replace(u"\u2225",u"\u2016")
            dd = dd.replace(u"\uff0d",u"\u2212")
            dd = dd.replace(u"\uffe0",u"\u00a2")
            dd = dd.replace(u"\uffe1",u"\u00a3")
            dd = dd.replace(u"\uffe2",u"\u00ac") 
            dd = dd.replace(u"\u3231",u"\u682a") 
            # 書き込む
            fout.write(dd + '\n')
        fout.close()

        sg.popup('作成しました',title='終了')

window.close()

ちょいとつぶやき

csvファイルを作るところで、同じ操作をしているので、関数にした方がスッキリするのですが、同じ操作になる理由が良く分からないので、そのままにしております。
文字コードが関係しているような気もするのですが、とりあえず動くからまぁいいか、って感じです。
フォルダが一つ下がっているので、配列としては、一つ後ろになる気がするのですが、どうも違うらしい。

あと、UTF-8からSJISに変換できない文字があるので、変換前に置換しておく必要がありました。
まぁ、UTF-8で全部処理しろよ、って話もあるかと思いますが、それが通るような職場環境ではないので、仕方がないところですな。