バグる例
例えば、Accessと同フォルダにいるCSVファイルに対して、サブフォルダ『backup』に同名ファイルが存在するかチェックする機能です。
Private Function dir_test_1()
Dim buf_ As String
'Accessと同フォルダにいるCSVを全部チェックするぞい
buf_ = Dir(CurrentProject.Path & "\*.csv")
Do While buf_ <> ""
'★ここの判定でDirを再使用しているのがヤバい!
If Dir(CurrentProject.Path & "\backup\" & buf_) <> "" Then
Debug.Print "バックアップ先フォルダに" & buf_ & "いるよ!"
End If
'最初に処理するCSVと同名ファイルがバックアップフォルダにいる?
'いる ⇒ 1ファイル目だけで Do While ループ抜けちゃう
'いない ⇒ 後述の buf_ = Dir() で例外発生
buf_ = Dir()
Loop
End Function
Accessと同フォルダにいるCSVファイルが1つだけで、 If Dir(……
がTrueになる条件だと正常終了してしまうん。
別関数でDir関数を使ったらどうなる?
例えばこんな感じ。
ファイル存在チェックを別関数に切り分けしてみました。
'Accessと同フォルダに居るCSVに対してbackupフォルダに居たらなんかする
Private Function dir_test_2()
Dim buf_ As String
'Accessと同フォルダにいるCSVを全部チェックするぞい
buf_ = Dir(CurrentProject.Path & "\*.csv")
Do While buf_ <> ""
'ファイルの存在チェックは別関数にやらせるよ
If is_file_exist(CurrentProject.Path & "\backup\" & buf_) <> "" Then
Debug.Print "バックアップ先フォルダに" & buf_ & "いるよ!"
End If
buf_ = Dir()
Loop
End Function
'ファイルパスをもらってファイルが存在するか返すよ
Private Function is_file_exist(ByVal file_path As String)
is_file_exist = Dir(file_path) <> ""
End Function
結果は『バグる例』と同じ。
Dirを呼び出すのが、別関数であろうと(スコープが変わろうと)同じです(´・ω・`)
つまり、こういう使い方はバグを生み出しやすいので注意
下記のようなコードはDo While内でDir関数を再使用していないか 人が気を付けて 作る必要があります。
Dim buf_ As String
buf_ = Dir("ファイル一覧を取得するワイルドカード的な文字列")
Do While buf_ <> ""
'buf_ = Dir()に到達するまでにDir()を再使用していないか『人が』注意して作る必要がある。
buf_ = Dir()
Loop
Do While内(浅い階層)でDir関数の再使用を発見できればいんですが……。
Do While内で呼び出した関数内で呼び出した関数内 でDir関数を使ってたりなんかして……。
うーん、バグの香りがプンプンします(´・ω・`)
蛇足
個人的にDir関数は使わないようにしています。
Dir関数の仕様を知らない人がシステム改修するかもしれないから…。
代わりに FileSystemObject クラスを使っています。使用例は下記。
AccessのVBAでフォルダー内ハウスキープ(古いファイルを自動削除)関数
あと、複数ファイルを処理する機能はテストもちゃんと複数ファイル用意しましょう。
(そのへん横着しちゃダメね)
バージョン
Windows10 Pro バージョン1909 OSビルド19042.630
Access for Microsoft 365 MSO(16.0.13328.20334)32ビット