2021年6月28日月曜日

WMIでファイルとフォルダの作成・改名を検知して名前に更新日時を入れる

WMIでファイルやフォルダの作成・改名イベントを検出して、対象アイテムの名前に応じて処理を切り替えるサンプルを作成しました。



動機


あるプログラムが起動すると、その時の年月日にもとづく名前のフォルダが作成されます。(例えば2021.06.28)
そのフォルダの中にファイルが次々と追加されていくのですが、ある操作を行うと出力ファイル名に含まれる連番部分がリセットされてしまい、本来上書きするべきでないデータを上書きしてしまいます。
ファイル名に、更新日時の情報を入れれば、連番部分がリセットされたとしても上書きされることは回避できるので、そのようにしました。


WMIでファイルの作成・改名イベントを検知する最もシンプルなサンプル


上記サンプルでは「C:\test」フォルダ内で以下のイベントが発生した際にメッセージが表示されます。
  • ファイルの追加
  • ファイルの改名

フォルダの追加・改名を検知したい場合は「CIM_DataFile」の部分を「CIM_Directory」にします。

お世話になったサイト
JScript (WSH) でフォルダ監視 - by edvakf in hatena


3回連続して検出するサンプル


eventSrc.NextEvent()をコールすると、対象イベントが発生するまでプログラムは次のステップに進まないこと(同期的)が上記の実行結果から分かりました。



関数化


複数のファイルやフォルダを監視するためには関数にした方が使い勝手が良いです。
これ以降のサンプルは全角文字を含んでいるためSJIS形式で保存しないとwscript.exeでエラーになります。



フォルダを検知したら、その中のファイルを検知する


WQL実行後のWMIはcloseしたり「wmi = null」のような事をしなくても、次のWQLを実行できることが分かりました。



終了トリガー


プログラム使用中に日付が変わったら、出力先のフォルダ名も変わる(例えば「2021.06.28」から「2021.06.29」になる)のですが、一度eventSrc.NextEvent()をコールすると対象フォルダ内でイベントが発生するまでスクリプトは次のステップに進むことができません。
イベント監視を始める前に、任意のタイミングで終了トリガーが出現してイベント検知されるように予約する仕組みを作りました。



更新日時にリネーム


リネーム処理でもファイル変更イベントが発生するので、リネーム済みかどうかを判定しないと無限ループになってしまう点が要注意です。



日付が変わるまでループ


フォルダとファイルのイベントを監視するループを追加しました。
ファイルのイベントを監視するループが継続している間はフォルダを監視するループは保留状態になります。(ファイル監視ループが終了するとフォルダ監視ループが再開します)



イベント発生前のチェック


今までのサンプルでは、サンプルプログラムが起動した後に発生したイベントのみを扱っていました。
しかし実際にはサンプルプログラムが起動する前に対象フォルダが作成されていたり、そのフォルダ内に対象ファイルが出来上がっている場合もあります。
イベントの監視を始める前に既存のフォルダとファイルをチェックする仕組みを追加しました。



script起動時の引数を使用


監視するフォルダのpathを、script起動時の引数から取得できるように変更して、完成です。



スモールステップは、大事


今回のサンプルの作成を開始する前の段階では、正直なところ1~2時間くらいで完成できると思っていました。
しかし実際には10時間くらいかかってしまいました。
想定よりも時間がかかってしまった要因の比率として大きいのは単体テストを省略したことでした。
単体テスト(ユニットテスト)とは | ソフトウェアの検証の種類 | テクマトリックス株式会社


具体的には以下のような点で躓きました。
  • wmiはcloseしたり「wmi = null」をしなくても次のWQLが実行できる、という事をテストしていませんでした。本当はプログラムにミスがあった(ファイルイベントを監視したいのに引数を間違えてフォルダイベントを監視していた)のに、勘違いして「closeしたりnullの代入が必要なのかも?」と考えて時間を無駄にしました。
  • fs.GetFile(path).DateLastModifiedの返り値は文字列ではないのでreplaceメソッドが無い。しかしDateオブジェクトでもない。という事だけを確認する小さなサンプルを作って試すべきだったが、ファイルイベントの監視プログラムの中で確認したために関係ない部分の動作にかかった時間を無駄にしました。

勘違いした事によって「プロセスを分けて標準出力を使って通信する方法」を模索したりした結果、標準出力の使用時の注意事項を再認識したりもしたので「勘違いが解けるまでの時間は全て無駄だった」とも言い切れないのですが、心理的には減らせるところは減らしたい感じです。

このような、サンプル作成過程も、同じような事で悩む人にとっては有益な情報になり得るかと思い、投稿してみました。



0 件のコメント:

コメントを投稿