0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AccessのVBAでDir関数使ってファイル一覧ループする時はDir関数の再使用に注意!

Last updated at Posted at 2020-11-28

バグる例

例えば、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ビット

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?