重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

VBA超初心者なりに記述したのですが、どうしたらいいのかわからないのでお助けください。
例えば以下のような一定の命名規則のファイルが、r:\testに複数あります。

0123-20140301-abcd.txt
0124-20140302-efgh.txt
xxxx-20140301.csv
xxxx-20140302.csv

「通し番号4桁-日付8桁-4桁(不定).txt」に対応する「xxxx(固定)-日付8桁.csv」のファイルがあるかチェックしたいだけなのですが、以下の記述では一番古い日付の1個しかチェックしてくれません。

''''''''''''''''''''''''''''''''''''''''''''''''''
 Dim buf As String
 Dim cnt As Long

 buf = Dir("r:\test\????-20*.txt")

Do While buf <> ""

 If Dir("r:\test\xxxx-" & Mid(buf, 6, 8) & ".csv") <> "" Then
 Call MsgBox(buf & "が存在します")
 End If

 cnt = cnt + 1
 buf = Dir()
Loop

  Call MsgBox(cnt & "個のファイルをチェック済み")

''''''''''''''''''''''''''''''''''''''''''''''''''

「xxxx-20140301.csv」が存在しない場合は「1個のファイルをチェック済み」と出て終わります。
本当は2個のファイルをチェックしてほしいのです。

なお、実際にファイルが何個あるかはその時々なので、いつでも使えるようにForNextではなくDoLoopを選びました。
If~Endifがなければ「2個のファイルをチェック済み」と出るので、その部分の記述が怪しいとは思うのですが。

なお、自宅のPCにはExcelがないので、VB2010Expressを入れて再現してみました。
msgboxの記述方法が違うくらいで、後は職場で悩んでいた内容そのままです。
どうぞよろしくお願いします。

A 回答 (2件)

Dir 関数は、同一パスで繰り返し呼び出す場合、引数を書かずに実行するわけですが、その際、最後に指定していたパスで呼び出されることになります。

つまり引数なしとすると、テキストファイルと CSV ファイルのパスで交互に検索するというのは、できないということになりますね。

また、引数ありで繰り返し実行しても、続きのファイルはヒットせず、Dir はずっと最初のファイル名を返し続けるので、「一番古い日付の1個」のみといった動作になります。

下のコードでは、いったん全てのテキストファイルのファイル名を動的配列の中にためておいて、それが終わってから、対応する CSV を探し始めるという手順にしています。これで様子を見てください。


Sub Macro1()
  Dim p As String, textFileName As String, csvFileName As String, a() As String, cnt1 As Long, cnt2 As Long, i As Long
  p = "r:\test\????-20*.txt"
  textFileName = Dir(p)
  ReDim a(0) As String
  a(0) = textFileName
  Do While textFileName <> ""
    cnt1 = cnt1 + 1
    textFileName = Dir()
    ReDim Preserve a(cnt1) As String
    a(cnt1) = textFileName
  Loop
  For i = 0 To cnt1
    If a(i) <> "" Then
      csvFileName = Dir("r:\test\xxxx-" & Mid(a(i), 6, 8) & ".csv")
      If csvFileName <> "" Then
        MsgBox csvFileName & " が存在します"
        cnt2 = cnt2 + 1
      End If
    End If
  Next i
  MsgBox cnt2 & " 個の CSV ファイルを検出しました"
End Sub

この回答への補足

早速のご回答、ありがとうございます。
dir()でloop中にdir関数を使用したときの振舞いの謎が氷解し、感謝いたします。
変数に全ファイル名を入れて比較というのは先週試行錯誤していたときに思いついたのですが、ファイル数が不定なのでどれだけの変数を用意すればいいのかわからずあきらめていました。
動的配列のことを知り、勉強になりました。
ところでご教示いただいた内容をVBにそのままコピーして実行したところ、「配列変数を宣言するために'ReDim'ステートメントを使用することはできません」というエラーになりました。
ReDimとエラーについて調べたところ、最初の「Dim a() As String」だけで、a(0)やa(1)などを改めて宣言しなおす必要はないようです。
「As String」の部分だけを削ったら正常に動作しました。
ExcelのVBAだと宣言する必要があるのでしょうか。週明けに職場で試してみます。

補足日時:2014/03/09 13:33
    • good
    • 0

>ReDimとエラーについて調べたところ、最初の「Dim a() As String」だけで、a(0)やa(1)などを改めて宣言しなおす必要はないようです。




すみません。おっしゃるとおりで、データ型を変更できるのは、Variant 型の変数のみです。ヘルプの「ReDim ステートメント」のページでもそのように説明されています。したがって 2 回目以降の「As String」は変更してないのでエラーにまではなりませんが、不要ですね。

注意点としては、Dim ステートメントにおいて始めから Variant の動的配列として宣言していて ReDim でデータ型を変更することは、できないということです。Dim において配列でない Variant の変数を宣言していて ReDim でデータ型を変更することは、できます。つまり () の有無により、エラーになったりならなかったりします。また、Variant の変数であっても、Preserve が付いていると変更できません。

成功

Dim a() As Long
ReDim a(0)
ReDim a(1)

成功

Dim a() As Long
ReDim a(0) As Long
ReDim a(1) As Long

エラー

Dim a() As Variant
ReDim a(0) As Long
ReDim a(1) As String

成功

Dim a As Variant
ReDim a(0) As Long
ReDim a(1) As String

エラー

Dim a As Variant
ReDim a(0) As Long
ReDim Preserve a(1) As String

エラー

Dim a As Long
ReDim a(0) As Long
    • good
    • 0
この回答へのお礼

variantの動的配列の再宣言のエラーについて、わざわざ試していただいてありがとうございます。
とは言え初心者ゆえvariant型の使いどころは理解が浅く、文字列や数列とはっきりしているときにはstringやlongを使う、としか考えておりません。

a() As Variant
a(1) = "data"
a(2) = 123

のようなデータがあれば、

b As String
b = a(1)
c As Long
c = a(2)

として別の変数に割り当てないと、むしろわからなくなってしまいます。申し訳ありません。

なお、学ばせていただいた通りに動的配列を試したところ、意図した動きをさせることができました。
すべてのファイル名をexcelのセルに出したり、解凍していないzipだけを解凍させるようなことも簡単にできました。
重ねてお礼申し上げます。
また何かございましたらよろしくお願いいたします。

お礼日時:2014/03/11 22:33

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!