WMIでファイルやフォルダの作成・改名イベントを検出して、対象アイテムの名前に応じて処理を切り替えるサンプルを作成しました。
動機
あるプログラムが起動すると、その時の年月日にもとづく名前のフォルダが作成されます。(例えば2021.06.28)
そのフォルダの中にファイルが次々と追加されていくのですが、ある操作を行うと出力ファイル名に含まれる連番部分がリセットされてしまい、本来上書きするべきでないデータを上書きしてしまいます。
ファイル名に、更新日時の情報を入れれば、連番部分がリセットされたとしても上書きされることは回避できるので、そのようにしました。
WMIでファイルの作成・改名イベントを検知する最もシンプルなサンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computer = '.' | |
drive = 'C:' | |
path = '\\test\\' | |
wmi = GetObject("winmgmts:\\\\" + computer + "\\root\\CIMV2") | |
wql = [ | |
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE ", | |
"Targetinstance ISA 'CIM_DataFile' AND ", | |
"TargetInstance.Drive = '" + drive + "' AND ", | |
"TargetInstance.Path = '" + path.replace(/\\/g,'\\\\') + "'" | |
].join('') | |
eventSrc = wmi.ExecNotificationQuery(wql) | |
eventObj = eventSrc.NextEvent() | |
objItem = eventObj.TargetInstance | |
path = objItem.Name | |
WScript.Echo(path) // C:\test\new file.txt |
- ファイルの追加
- ファイルの改名
フォルダの追加・改名を検知したい場合は「CIM_DataFile」の部分を「CIM_Directory」にします。
お世話になったサイト
JScript (WSH) でフォルダ監視 - by edvakf in hatena
3回連続して検出するサンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computer = '.' | |
drive = 'C:' | |
path = '\\test\\' | |
wmi = GetObject("winmgmts:\\\\" + computer + "\\root\\CIMV2") | |
wql = [ | |
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE ", | |
"Targetinstance ISA 'CIM_DataFile' AND ", | |
"TargetInstance.Drive = '" + drive + "' AND ", | |
"TargetInstance.Path = '" + path.replace(/\\/g,'\\\\') + "'" | |
].join('') | |
eventSrc = wmi.ExecNotificationQuery(wql) | |
arr = [] | |
i = 0 | |
while(i < 3){ | |
eventObj = eventSrc.NextEvent() | |
objItem = eventObj.TargetInstance | |
path = objItem.Name | |
arr[i++] = path | |
} | |
WScript.Echo(arr.join('\n')) |
関数化
複数のファイルやフォルダを監視するためには関数にした方が使い勝手が良いです。
これ以降のサンプルは全角文字を含んでいるためSJIS形式で保存しないとwscript.exeでエラーになります。
フォルダを検知したら、その中のファイルを検知する
WQL実行後のWMIはcloseしたり「wmi = null」のような事をしなくても、次のWQLを実行できることが分かりました。
終了トリガー
プログラム使用中に日付が変わったら、出力先のフォルダ名も変わる(例えば「2021.06.28」から「2021.06.29」になる)のですが、一度eventSrc.NextEvent()をコールすると対象フォルダ内でイベントが発生するまでスクリプトは次のステップに進むことができません。
イベント監視を始める前に、任意のタイミングで終了トリガーが出現してイベント検知されるように予約する仕組みを作りました。
更新日時にリネーム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// このスクリプトはUTF-8で保存すると実行時エラーになってしまう。 | |
// SJISで保存すること。 | |
function echo(str){ WScript.echo(str) } | |
function wmi(path, isDir){ | |
// path : 監視対象のフォルダのpath | |
// isDir : フォルダの追加・変更を検知したい場合はtrue。ファイルの場合はfalse | |
var ma = path.match(/^([A-Z]:)(.+)\\?$/) | |
if(!ma){return echo('error. この関数はローカルドライブ専用です。')} | |
var computer = '.' | |
var drive = ma[1] | |
var path = ma[2] + '\\' | |
var タイプ = isDir ? 'Directory' : 'DataFile' | |
var wmi = GetObject("winmgmts:\\\\" + computer + "\\root\\CIMV2") | |
var wql = [ | |
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE ", | |
"Targetinstance ISA 'CIM_" + タイプ + "' AND ", | |
"TargetInstance.Drive = '" + drive + "' AND ", | |
"TargetInstance.Path = '" + path.replace(/\\/g,'\\\\') + "'" | |
].join('') | |
var eventSrc = wmi.ExecNotificationQuery(wql) | |
return eventSrc | |
} | |
function イベントを監視(path, isDir){ | |
var eventSrc = wmi(path, isDir) | |
var eventObj = eventSrc.NextEvent() | |
var objItem = eventObj.TargetInstance | |
var path = objItem.Name | |
return path | |
} | |
AXO = function(str){return new ActiveXObject(str)} | |
終了トリガー = function(){ | |
var path | |
var 待機秒数 | |
var dat待機開始 | |
var タイプ | |
var path親 = WScript.ScriptFullName.replace(/\\[^\\]+$/,'\\') | |
var path遅延操作 = path親 + "遅延操作.js" | |
var shell = AXO('WScript.Shell') | |
return { | |
予約 : function(path対象, 秒数, isDir){ | |
path = path対象 + '\\終了トリガー' | |
待機秒数 = 秒数 | |
タイプ = isDir | |
dat待機開始 = new Date() | |
shell.run('"' + [path遅延操作, path, 秒数, isDir ? 'dir' : 'file', 'create'].join('" "') + '"') | |
}, | |
キャンセル : function(){ | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat待機開始, dat現在) | |
if(待機秒数 < 経過秒数){return} | |
shell.run('"' + [path遅延操作, path, (待機秒数 - 経過秒数 + 1), タイプ ? 'dir' : 'file', 'del'].join('" "') + '"') | |
}, | |
判定 : function(p){ | |
if(p.toUpperCase() != path.toUpperCase()){return} | |
ファイルシステム[(タイプ ? 'フォルダ' : 'ファイル')+'削除'](path) | |
path = null | |
return true | |
} | |
} | |
}() | |
ファイルシステム = function(){ | |
var fs = AXO('Scripting.FileSystemObject') | |
return { | |
ファイル削除 : function(path){ | |
fs.DeleteFile(path) | |
}, | |
フォルダ削除 : function(path){ | |
fs.DeleteFolder(path) | |
}, | |
ファイル名変更 : function(path, ファイル名){ | |
var pathBase = path.replace(/[^\\\/]+$/,'') + ファイル名 | |
var num = 1 | |
var pathAfter = pathBase | |
while(fs.FileExists(pathAfter)){ | |
pathAfter = pathBase.replace(/(\.[^.]+$)/,'-'+num+'$1') | |
num++ | |
} | |
fs.MoveFile(path, pathAfter) | |
return pathAfter | |
}, | |
get最終更新日時 : function(path){ | |
return fs.GetFile(path).DateLastModified | |
} | |
} | |
}() | |
function get経過秒数(datBefore, datAfter){ | |
return Math.floor((datAfter.getTime() - datBefore.getTime()) / 1000) | |
} | |
function ファイル名に更新日時を入れる(path){ | |
var ファイル名before = path.match(/[^\\\/]+$/)[0] | |
if(ファイル名before.match(/^\d{8} \d{6}_/)){ return path } // リネーム済みファイルは無視 | |
var dat更新 = new Date(ファイルシステム.get最終更新日時(path)) | |
// 更新直後だと書き込み中かもしれないので少し待機する | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat更新, dat現在) | |
if(経過秒数 < 5){ WScript.Sleep(1000 * (5 - Math.floor(経過秒数))) } | |
var ファイル名 = get日時(dat更新).replace(/[\/:]/g,'') + '_' + path.match(/[\\\/]([^\\\/]+)$/)[1] | |
var pathAfter = ファイルシステム.ファイル名変更(path, ファイル名) | |
return pathAfter | |
} | |
function 桁(num, 桁数){ | |
var str0=num+'', str1=Array(桁数+1).join(0)+num | |
return (桁数 < str0.length) ? str0 : str1.slice(str1.length-桁数,str1.length) | |
} | |
function get日時(dat){ | |
dat = dat || new Date() | |
with(dat){ return [getFullYear(), 桁(getMonth()+1,2), 桁(getDate(),2)].join('/') + ' ' + [桁(getHours(),2), 桁(getMinutes(),2), 桁(getSeconds(),2)].join(':') } | |
} | |
function main(path){ | |
終了トリガー.予約(path, 10, true) | |
pathDir = イベントを監視(path, true) | |
if(終了トリガー.判定(pathDir)){ return echo(path + '\n\n上記Pathでは10秒間イベントはありませんでした。') } | |
終了トリガー.キャンセル() | |
終了トリガー.予約(pathDir, 10) | |
pathFile = イベントを監視(pathDir) | |
if(終了トリガー.判定(pathFile)){ return echo(pathDir + '\n\n上記Pathでは10秒間イベントはありませんでした。') } | |
終了トリガー.キャンセル() | |
var pathAfter = ファイル名に更新日時を入れる(pathFile) | |
WScript.Echo([ | |
'dir > ' + pathDir, | |
'file > ' + pathFile, | |
'ren > ' + pathAfter | |
].join('\n')) | |
} | |
main('C:\\test') |
日付が変わるまでループ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// このスクリプトはUTF-8で保存すると実行時エラーになってしまう。 | |
// SJISで保存すること。 | |
function echo(str){ WScript.echo(str) } | |
function wmi(path, isDir){ | |
// path : 監視対象のフォルダのpath | |
// isDir : フォルダの追加・変更を検知したい場合はtrue。ファイルの場合はfalse | |
var ma = path.match(/^([A-Z]:)(.+)\\?$/) | |
if(!ma){return echo('error. この関数はローカルドライブ専用です。')} | |
var computer = '.' | |
var drive = ma[1] | |
var path = ma[2] + '\\' | |
var タイプ = isDir ? 'Directory' : 'DataFile' | |
var wmi = GetObject("winmgmts:\\\\" + computer + "\\root\\CIMV2") | |
var wql = [ | |
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE ", | |
"Targetinstance ISA 'CIM_" + タイプ + "' AND ", | |
"TargetInstance.Drive = '" + drive + "' AND ", | |
"TargetInstance.Path = '" + path.replace(/\\/g,'\\\\') + "'" | |
].join('') | |
var eventSrc = wmi.ExecNotificationQuery(wql) | |
return eventSrc | |
} | |
function イベントを監視(path, isDir, func){ | |
var eventSrc = wmi(path, isDir) | |
while(true){ | |
var eventObj = eventSrc.NextEvent() | |
var objItem = eventObj.TargetInstance | |
var path = objItem.Name | |
if(func(path)){return} | |
} | |
} | |
AXO = function(str){return new ActiveXObject(str)} | |
終了トリガー = function(){ | |
var path | |
var 待機秒数 | |
var dat待機開始 | |
var タイプ | |
var path親 = WScript.ScriptFullName.replace(/\\[^\\]+$/,'\\') | |
var path遅延操作 = path親 + "遅延操作.js" | |
var shell = AXO('WScript.Shell') | |
return { | |
予約 : function(path対象, 秒数, isDir){ | |
path = path対象 + '\\終了トリガー' | |
待機秒数 = 秒数 | |
タイプ = isDir | |
dat待機開始 = new Date() | |
shell.run('"' + [path遅延操作, path, 秒数, isDir ? 'dir' : 'file', 'create'].join('" "') + '"') | |
}, | |
キャンセル : function(){ | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat待機開始, dat現在) | |
if(待機秒数 < 経過秒数){return} | |
shell.run('"' + [path遅延操作, path, (待機秒数 - 経過秒数 + 1), タイプ ? 'dir' : 'file', 'del'].join('" "') + '"') | |
}, | |
判定 : function(p){ | |
if(p.toUpperCase() != path.toUpperCase()){return} | |
ファイルシステム[(タイプ ? 'フォルダ' : 'ファイル')+'削除'](path) | |
path = null | |
return true | |
} | |
} | |
}() | |
ファイルシステム = function(){ | |
var fs = AXO('Scripting.FileSystemObject') | |
return { | |
ファイル削除 : function(path){ | |
fs.DeleteFile(path) | |
}, | |
フォルダ削除 : function(path){ | |
fs.DeleteFolder(path) | |
}, | |
ファイル名変更 : function(path, ファイル名){ | |
var pathBase = path.replace(/[^\\\/]+$/,'') + ファイル名 | |
var num = 1 | |
var pathAfter = pathBase | |
while(fs.FileExists(pathAfter)){ | |
pathAfter = pathBase.replace(/(\.[^.]+$)/,'-'+num+'$1') | |
num++ | |
} | |
fs.MoveFile(path, pathAfter) | |
return pathAfter | |
}, | |
get最終更新日時 : function(path){ | |
return fs.GetFile(path).DateLastModified | |
} | |
} | |
}() | |
function get経過秒数(datBefore, datAfter){ | |
return Math.floor((datAfter.getTime() - datBefore.getTime()) / 1000) | |
} | |
function ファイル名に更新日時を入れる(path){ | |
var ファイル名before = path.match(/[^\\\/]+$/)[0] | |
if(ファイル名before.match(/^\d{8} \d{6}_/)){ return path } // リネーム済みファイルは無視 | |
var dat更新 = new Date(ファイルシステム.get最終更新日時(path)) | |
// 更新直後だと書き込み中かもしれないので少し待機する | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat更新, dat現在) | |
if(経過秒数 < 5){ WScript.Sleep(1000 * (5 - Math.floor(経過秒数))) } | |
var ファイル名 = get日時(dat更新).replace(/[\/:]/g,'') + '_' + path.match(/[\\\/]([^\\\/]+)$/)[1] | |
var pathAfter = ファイルシステム.ファイル名変更(path, ファイル名) | |
return pathAfter | |
} | |
function 桁(num, 桁数){ | |
var str0=num+'', str1=Array(桁数+1).join(0)+num | |
return (桁数 < str0.length) ? str0 : str1.slice(str1.length-桁数,str1.length) | |
} | |
function get日時(dat){ | |
dat = dat || new Date() | |
with(dat){ return [getFullYear(), 桁(getMonth()+1,2), 桁(getDate(),2)].join('/') + ' ' + [桁(getHours(),2), 桁(getMinutes(),2), 桁(getSeconds(),2)].join(':') } | |
} | |
function loopDir(path){ | |
echo('dir > ' + path) | |
var 今日の年月日 = get日時().replace(/\//g,'.').replace(/([\d.]+) .+/,'$1') | |
var フォルダ名 = path.match(/[^\\\/]+$/)[0] | |
if(フォルダ名.indexOf(今日の年月日)!=0){ return } // loop継続 > 次のdir作成・変更イベントを待つ | |
終了トリガー.予約(path, get日付が変わるまでの秒数(), false) | |
イベントを監視(path, false, loopFile) | |
// loopFileのループが完了したらloopDirのループが再開する | |
} | |
function loopFile(path){ | |
echo('file > ' + path) | |
if(終了トリガー.判定(path)){ return true } // loop中断 | |
ファイル名に更新日時を入れる(path) | |
} | |
get日付が変わるまでの秒数 = function(){ | |
with(new Date()){ var 日付が変わるまでの秒数 = ((24 - getHours()) * 60 - getMinutes()) * 60} | |
return 日付が変わるまでの秒数 | |
} | |
イベントを監視('C:\\test', true, loopDir) |
ファイルのイベントを監視するループが継続している間はフォルダを監視するループは保留状態になります。(ファイル監視ループが終了するとフォルダ監視ループが再開します)
イベント発生前のチェック
今までのサンプルでは、サンプルプログラムが起動した後に発生したイベントのみを扱っていました。
しかし実際にはサンプルプログラムが起動する前に対象フォルダが作成されていたり、そのフォルダ内に対象ファイルが出来上がっている場合もあります。
イベントの監視を始める前に既存のフォルダとファイルをチェックする仕組みを追加しました。
script起動時の引数を使用
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// このスクリプトはUTF-8で保存すると実行時エラーになってしまう。 | |
// SJISで保存すること。 | |
function echo(str){ WScript.echo(str) } | |
function wmi(path, isDir){ | |
// path : 監視対象のフォルダのpath | |
// isDir : フォルダの追加・変更を検知したい場合はtrue。ファイルの場合はfalse | |
var ma = path.match(/^([A-Z]:)(.+)\\?$/) | |
if(!ma){return echo('error. この関数はローカルドライブ専用です。')} | |
var computer = '.' | |
var drive = ma[1] | |
var path = ma[2] + '\\' | |
var タイプ = isDir ? 'Directory' : 'DataFile' | |
var wmi = GetObject("winmgmts:\\\\" + computer + "\\root\\CIMV2") | |
var wql = [ | |
"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE ", | |
"Targetinstance ISA 'CIM_" + タイプ + "' AND ", | |
"TargetInstance.Drive = '" + drive + "' AND ", | |
"TargetInstance.Path = '" + path.replace(/\\/g,'\\\\') + "'" | |
].join('') | |
var eventSrc = wmi.ExecNotificationQuery(wql) | |
return eventSrc | |
} | |
function イベントを監視(path, isDir, func){ | |
var eventSrc = wmi(path, isDir) | |
while(true){ | |
var eventObj = eventSrc.NextEvent() | |
var objItem = eventObj.TargetInstance | |
var path = objItem.Name | |
if(func(path)){return} | |
} | |
} | |
AXO = function(str){return new ActiveXObject(str)} | |
終了トリガー = function(){ | |
var path | |
var 待機秒数 | |
var dat待機開始 | |
var タイプ | |
var path親 = WScript.ScriptFullName.replace(/\\[^\\]+$/,'\\') | |
var path遅延操作 = path親 + "遅延操作.js" | |
return { | |
予約 : function(path対象, 秒数, isDir){ | |
path = path対象 + '\\終了トリガー' | |
待機秒数 = 秒数 | |
タイプ = isDir | |
dat待機開始 = new Date() | |
shell.run('"' + [path遅延操作, path, 秒数, isDir ? 'dir' : 'file', 'create'].join('" "') + '"') | |
}, | |
キャンセル : function(){ | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat待機開始, dat現在) | |
if(待機秒数 < 経過秒数){return} | |
shell.run('"' + [path遅延操作, path, (待機秒数 - 経過秒数 + 1), タイプ ? 'dir' : 'file', 'del'].join('" "') + '"') | |
}, | |
判定 : function(p){ | |
if(p.toUpperCase() != (path || '').toUpperCase()){return} | |
ファイルシステム[(タイプ ? 'フォルダ' : 'ファイル')+'削除'](path) | |
path = null | |
return true | |
} | |
} | |
}() | |
ファイルシステム = function(){ | |
var fs = AXO('Scripting.FileSystemObject') | |
return { | |
ファイル削除 : function(path){ | |
fs.DeleteFile(path) | |
}, | |
フォルダ削除 : function(path){ | |
fs.DeleteFolder(path) | |
}, | |
ファイル名変更 : function(path, ファイル名){ | |
var pathBase = path.replace(/[^\\\/]+$/,'') + ファイル名 | |
var num = 1 | |
var pathAfter = pathBase | |
while(fs.FileExists(pathAfter)){ | |
pathAfter = pathBase.replace(/(\.[^.]+$)/,'-'+num+'$1') | |
num++ | |
} | |
fs.MoveFile(path, pathAfter) | |
return pathAfter | |
}, | |
get最終更新日時 : function(path){ | |
return fs.GetFile(path).DateLastModified | |
} | |
} | |
}() | |
function get経過秒数(datBefore, datAfter){ | |
return Math.floor((datAfter.getTime() - datBefore.getTime()) / 1000) | |
} | |
function ファイル名に更新日時を入れる(path){ | |
var ファイル名before = path.match(/[^\\\/]+$/)[0] | |
if(ファイル名before.match(/^\d{8} \d{6}_/)){ return path } // リネーム済みファイルは無視 | |
var dat更新 = new Date(ファイルシステム.get最終更新日時(path)) | |
// 更新直後だと書き込み中かもしれないので少し待機する | |
var dat現在 = new Date() | |
var 経過秒数 = get経過秒数(dat更新, dat現在) | |
if(経過秒数 < 5){ WScript.Sleep(1000 * (5 - Math.floor(経過秒数))) } | |
var ファイル名 = get日時(dat更新).replace(/[\/:]/g,'') + '_' + path.match(/[\\\/]([^\\\/]+)$/)[1] | |
var pathAfter = ファイルシステム.ファイル名変更(path, ファイル名) | |
return pathAfter | |
} | |
function 桁(num, 桁数){ | |
var str0=num+'', str1=Array(桁数+1).join(0)+num | |
return (桁数 < str0.length) ? str0 : str1.slice(str1.length-桁数,str1.length) | |
} | |
function get日時(dat){ | |
dat = dat || new Date() | |
with(dat){ return [getFullYear(), 桁(getMonth()+1,2), 桁(getDate(),2)].join('/') + ' ' + [桁(getHours(),2), 桁(getMinutes(),2), 桁(getSeconds(),2)].join(':') } | |
} | |
function loopDir(path){ | |
echo('dir > ' + path) | |
var 今日の年月日 = get日時().replace(/\//g,'.').replace(/([\d.]+) .+/,'$1') | |
var フォルダ名 = path.match(/[^\\\/]+$/)[0] | |
if(フォルダ名.indexOf(今日の年月日)!=0){ return } // loop継続 > 次のdir作成・変更イベントを待つ | |
var arrFile = shell.getDir(path) | |
for0L(arrFile, function(i, ファイル名){ loopFile(path + '\\' + ファイル名) }) | |
終了トリガー.予約(path, get日付が変わるまでの秒数(), false) | |
イベントを監視(path, false, loopFile) | |
// loopFileのループが完了したらloopDirのループが再開する | |
} | |
function loopFile(path){ | |
echo('file > ' + path) | |
if(終了トリガー.判定(path)){ return true } // loop中断 | |
ファイル名に更新日時を入れる(path) | |
} | |
get日付が変わるまでの秒数 = function(){ | |
with(new Date()){ var 日付が変わるまでの秒数 = ((24 - getHours()) * 60 - getMinutes()) * 60} | |
return 日付が変わるまでの秒数 | |
} | |
shell = function(){ | |
var shell = AXO('WScript.Shell') | |
return { | |
getDir:function(path, swDir, swSub){ | |
var arr = shell.exec('cmd /C dir /A'+(swDir?'':'-')+'D /B'+(swSub?' /S':'')+' "'+path.replace(/[/]/g,'\\')+'"').StdOut.ReadAll().split('\r\n').reverse() | |
!arr[0] && arr.shift() | |
return arr.reverse() | |
}, | |
run : function(cmd){ shell.run(cmd) } | |
} | |
}() | |
function for0L(arr, func){ | |
for(var i=0,L=arr.length; i<L ;i++){ | |
var res = func(i, arr[i]) | |
if(res){return res} | |
} | |
} | |
function main(){ | |
var arg = WScript.Arguments | |
if(arg.length==0){ return echo('対象フォルダをD&Dしてください') } | |
var path = arg(0) | |
var arrDir = shell.getDir(path, true) | |
for0L(arrDir, function(i, フォルダ名){ loopDir(path + '\\' + フォルダ名) }) | |
イベントを監視(path, true, loopDir) | |
} | |
main() |
スモールステップは、大事
今回のサンプルの作成を開始する前の段階では、正直なところ1~2時間くらいで完成できると思っていました。
しかし実際には10時間くらいかかってしまいました。
想定よりも時間がかかってしまった要因の比率として大きいのは単体テストを省略したことでした。
単体テスト(ユニットテスト)とは | ソフトウェアの検証の種類 | テクマトリックス株式会社
具体的には以下のような点で躓きました。
- wmiはcloseしたり「wmi = null」をしなくても次のWQLが実行できる、という事をテストしていませんでした。本当はプログラムにミスがあった(ファイルイベントを監視したいのに引数を間違えてフォルダイベントを監視していた)のに、勘違いして「closeしたりnullの代入が必要なのかも?」と考えて時間を無駄にしました。
- fs.GetFile(path).DateLastModifiedの返り値は文字列ではないのでreplaceメソッドが無い。しかしDateオブジェクトでもない。という事だけを確認する小さなサンプルを作って試すべきだったが、ファイルイベントの監視プログラムの中で確認したために関係ない部分の動作にかかった時間を無駄にしました。
勘違いした事によって「プロセスを分けて標準出力を使って通信する方法」を模索したりした結果、標準出力の使用時の注意事項を再認識したりもしたので「勘違いが解けるまでの時間は全て無駄だった」とも言い切れないのですが、心理的には減らせるところは減らしたい感じです。
このような、サンプル作成過程も、同じような事で悩む人にとっては有益な情報になり得るかと思い、投稿してみました。
0 件のコメント:
コメントを投稿