質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.83%

VBA 指定フォルダの配下にあるファイルをすべて参照する処理について質問

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 2,380

King_of_Flies

score 314

お世話になっております。

下記参考サイトを元に、コードを作成しました。

http://officetanaka.net/excel/vba/file/file07.htm
>http://www.asahi-net.or.jp/~ef2o-inue/vba_o/sub05_110_120.html

Private Sub hoge(folderPath As String)
    Dim targetFileName As String 
  'ファイル名格納①
    targetFileName = Dir(folderPath & "\*.xlsx",vbNormal)

    Do while targetFileName <> ""
        'openfileは渡されたファイル名を持つファイルを開く処理です。
        Call openFile(targetFileName)

        '新しく開かれたtargetFileNameのBookオブジェクトを格納
        Dim targetWorkBook As WorkBook
        Set targetWorkBook = ActiveWorkBook

    '新しく開かれたtargetFileNameの一番目のシートオブジェクトを格納
        Dim targetWorkSheet As WorkSheet
     Set  targetWorkSheet = targetWorkBook.WorkSheets(1)

        'dataEditは渡されたシートオブジェクトのデータにいろいろ設定する
        Call dataEdit(targetWorkSheet)
      
         '開かれたファイルを閉じる
         Application.DisplayAlerts = False
         targetWorkBook.Close
         Application.DisplayAlerts = True 
     
     '--問題となっているところ。ファイル名格納②--
         targetFileName = Dir()     
    Loop     

End Sub


説明しやすいように、前提として
folderPath には2件のファイル「ふげ.xlsx」「ほげ.xlsx」があるとします。

参考のサイトの意図する通りに動作するのであれば、
①の処理でふげ.xlsxがtargetFileNameに格納され、
②の処理でほげ.xlsxがtargetFileNameに格納されること思うのですが、
①の処理は上手く動作し、②の処理ではtargetFileNameに""が入っています。

なぜ「ほげ.xlsx」が取れないのでしょうか。
どうぞよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+4

このような場合は、まずはシンプルなコードで動作確認して、次にコードを順次追加していって動作確認するということを繰り返して原因を特定しましょう。

下記のようにファイル名検索以外の部分をコメントアウトした場合、
イミディエイトにファイル名は出力されますか。

されたら、一つずつコメントアウトを外して、動作確認してください。希望のファイル名が出力されない場合、直前にコメントアウトを外してコードが原因です。

Private Sub hoge(folderPath As String)
    Dim targetFileName As String
    'ファイル名格納①
    targetFileName = Dir(folderPath & "\*.xlsx", vbNormal)

    Do While targetFileName <> ""
        Debug.Print targetFileName 'イミディエイトウィンドウへファイル名を出力
'        'openfileは渡されたファイル名を持つファイルを開く処理です。
'        Call openFile(targetFileName)
'
'        '新しく開かれたtargetFileNameのBookオブジェクトを格納
'        Dim targetWorkBook As Workbook
'        Set targetWorkBook = ActiveWorkbook
'
'        '新しく開かれたtargetFileNameの一番目のシートオブジェクトを格納
'        Dim targetWorkSheet As Worksheet
'         Set targetWorkSheet = targetWorkBook.Worksheets(1)
'
'        'dataEditは渡されたシートオブジェクトのデータにいろいろ設定する
'        Call dataEdit(targetWorkSheet)
'
'         '開かれたファイルを閉じる
'         Application.DisplayAlerts = False
'         targetWorkBook.Close
'         Application.DisplayAlerts = True

          '--問題となっているところ。ファイル名格納②--
         targetFileName = Dir()
    Loop

End Sub

原因の推測ですが、処理中にファイル名を変更したり、ファイル削除したりする処理が入ってませんか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/01 15:02 編集

    私からも回答投稿してしまいましたが、ほぼ間違いなくループ前に行ったワイルドカード指定のDirがファイル名指定のDirで上書かれているのが原因ですね。

    今回のhoge関数からの利用だけで考えれば、Dirで取得した(つまり存在することがわかっている)ファイル名をopenFile関数に渡しているので、開く前に改めて存在チェックをする必要性は薄いと思います。

    それでも開く前にファイル存在チェックをしたいのなら、FileSystemObjectのFileExistsを使うという方法もあります。

    openFile関数を変更したくない場合は、ExcelVBAerさんからのコメントにあるような方法など、ファイルをループする仕組みを変更する必要がありそうです。

    キャンセル

  • 2018/03/01 15:24

    Call先でDirを使っていたら、そりゃダメでしょう。そこまでは推測できなかった(;^ω^)
    Dirはこういうことがあるから注意しないと。ファイル名変更や削除,追加しても想定外の動作になることがありますので。
    今回は、Call先でDir自体必要ないと思いますが、思わぬバグの危険性がありますので、先にファイル名一覧を取得してから、それに対して処理をするようにするのが吉ですね。
    ExcelVBAerさんからのコメントの方法や、
    http://officetanaka.net/excel/vba/file/file07.htm
    の最後の方の「FileSystemObjectで取得する」方法などを使うといいでしょう。

    キャンセル

  • 2018/03/01 17:43

    皆様、ご回答ありがとうございます。

    無事、解決いたしました。
    今回は原因調査に一番役に立ちました「hatena19」様の回答をBAとさせていただきます。

    ありがとうございました。

    キャンセル

+1

ファイルの属性が違うとか?
Dir(folderPath & "\*.xlsx",vbNormal)
→ vbNormalだけ指定なので、隠しファイル、読取専用は対象外になりそう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/01 14:19

    あと、パスが長すぎると取れなくなるケースがあります(255くらいだったかな?)
    ※これに関しては詳しくないので、ご自分で調べてください~

    キャンセル

  • 2018/03/01 14:26

    パスが255を超えていることは無いので問題はないと思われます。
    また、ファイルの属性が違うという件ですが、
    ふげ.xlsxをコピーして作成した「ふげ -コピー.xlsx」をリネームして
    「ほげ.xlsx」に変更しただけなので、これも考えにくいと思います。

    キャンセル

  • 2018/03/01 14:35

    では、hatena19 さんが提示してるように、途中の処理を省いて再現するかどうかですね~

    キャンセル

+1

この流れで2ファイル目が取得できないのなら、おそらくループ内の他の処理をすべて省いて

    Dim targetFileName As String 
    'ファイル名格納①
    targetFileName = Dir(folderPath & "\*.xlsx",vbNormal)

    Do while targetFileName <> ""
        '【確認用】取得ファイル名をメッセージ表示
        Msgbox targetFileName

        '--問題となっているところ。ファイル名格納②--
        targetFileName = Dir()
    Loop  


としてもうまく取れないのではないでしょうか。
だとすれば怪しむべきはファイル名ということになるのですが。

Dirを疑う場合の確認事項

①2つめのファイル(ほげ.xlsx)はfolderPath内に存在していますか?
※↑さすがにこれは確認済みだと思いますが。。

②拡張子(半角で.xlsx)は正しいですか?
※↑例えば最近のマクロ付きブックは拡張子.xlsmです。
※このため様々なExcelブックを対象とする場合は拡張子*.xls*で抽出したりします。

targetFileName = Dir(folderPath & "\*.*",vbNormal)でならファイル取得できますか?
※↑これは.xlsx以外も取得されるため、オープン処理などは省いた状態で確認する必要があります。

まずはこのあたりを確認してみてはいかがでしょうか。

その他の怪しい点

targetFileName = Dir()でtargetFileName=""が取得されており、その結果Loopを抜けて処理終了していることまで確認できているのなら、この線はないので読み飛ばしてください。

もし「2ファイル目の処理が行われていないからtargetFileName=""が取得されているのだろう」と推測されているのなら、ちょっと違う可能性もあります。

コードがないので何とも言えませんが
Call openFile(targetFileName)
でブックをオープンした後に
Set targetWorkBook = ActiveWorkBook
でアクティブなブックを今回開いたブックとして扱っています。

この手法はしばしば行われている方法ではありますが、確実ではありません。
もしマクロを実行しているブックが何かの拍子でアクティブとなり、アクティブワークブックとして取得されてしまったら、targetWorkBook.Closeの時点でマクロは中断されることになります。
今回の場合「2ファイル目の処理が行われない」という点では2つめのファイルが取得できていないのと同じように感じるかもしれません。

試に
Set targetWorkBook = ActiveWorkBook
のあとに
Msgbox targetWorkBook.Name
を実行してみてください。
1件目の処理でちゃんと"ふげ.xlsx"を対象としていますでしょうか?

なお、開いたブックを取得する場合は、Workbook.Openの引数を取得するのが一番確実です。
またExcelは同じ名前のファイルを同時には開けいないため、開いた後にWorkbooks("ブック名")で取得するのも有効です。

参考になれば幸いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.83%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る