• ベストアンサー

Excelマクロでフォルダ内のCSVファイルを一括で読み込ませるには?

Excelファイルと同階層にあるCSVファイルを読み込ませるマクロを作ってみたのですが、正常に動作しません。 アドバイスいただければ幸いです。 Excel2003を使用しています。 Sub 同階層フォルダ内のCSV読込_Click() Dim fname As String 'ファイル名 Dim pathname As String 'パス名 Dim dat(1 To 4) As Variant '読み込んだデータ Dim rr As Long '対象行番号 Dim i As Integer '列のオフセット Dim j As Integer 'ファイル識別番号のオフセット '同階層フォルダ内のCSVファイルを参照 pathname = ".\*.csv" fname = Dir(pathname, vbNormal) 'データを挿入する行番号 rr = 2 '該当するファイルがある間 Do While fname <> "" j = 0 j = j + 1 'ファイルを開く Open fname For Input As #j 'ファイルの終端まで Do Until EOF(j) 'データを取得 Input #j, dat(1), dat(2), dat(3), dat(4) '読み込んだデータをセルに出力 For i = 1 To 4 Cells(rr, i).Value = dat(i) Next '行番号を更新 rr = rr + 1 Loop Close #j 'フォルダ内の次のファイルを検索 fname = Dir() Loop End Sub

質問者が選んだベストアンサー

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

こんにちは。 FileNo は、その都度閉じるのですから、FreeFile関数で、決めてあげれば、インクリメントする必要はありません。それから、私は、Line Input を使って、一行全体を取り入れて切り分けします。そのほうが速いからです。On Error があるのは、空行のためです。Dat()の配列を、String型にするのは、Excel側が勝手なキャストをしないためです。(Excel 2000以上) なお、一部の変数名は変更しました。プロシージャ名も英語に変更しました。なるべく、変数は、キャメル形式にしたほうがエラーを見つけやすいです。 Sub OpenCSV_in_SameFolder_Click()   Dim Fname As String   Dim PathName As String   Dim StartRow As Integer   Dim FileNo As Integer   Dim TextLine As String   Dim i As Long   Dim Dat() As String   PathName = ThisWorkbook.Path & "\"   Fname = Dir(PathName & "*.csv")   StartRow = 2   Do While Fname <> ""   FileNo = FreeFile()    Open PathName & Fname For Input As #FileNo     Do Until EOF(FileNo)      Line Input #FileNo, TextLine       Dat() = Split(TextLine, ",")       On Error Resume Next       '4列目までなら、Resize(,4).Valueとする       Cells(StartRow + i, 1).Resize(, UBound(Dat()) - LBound(Dat()) + 1).Value = Dat()       i = i + 1       On Error GoTo 0    Loop    Close #FileNo    Fname = Dir()   Loop End Sub

booooob
質問者

補足

目から鱗です。 コードの書き方を変えるだけでこれだけ見やすくなるのですね。 コメントを入れなくても分かりやすいです。 Line Input を使うと汎用性が高いですね。 こちらを利用させていただきます。 ところで、ご提示いただいたコードで私の知識不足により理解できない点が2箇所あります。 もしよろしければ、こちらもお教えいただけませんでしょうか。 ●Cells(StartRow + i, 1).Resize(, UBound(Dat()) - LBound(Dat()) + 1).Value = Dat()  これの意味がよく分かりません。  下記のコードと結果的に同じなのでしょうか?  For i = 0 To UBound(Dat()) If Len(Dat(i)) <> 0 Then Cells(StartRow, i + 1) = Dat(i) End If Next ●エラー処理の On Error Resume Next と On Error GoTo 0 を入れる場所ですが、  この位置に入れる理由をお教えいただけませんでしょうか?

その他の回答 (4)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.5

こんにちは。Wendy02です。 >●エラー処理の On Error Resume Next と On Error GoTo 0 を入れる場所ですが、 > この位置に入れる理由をお教えいただけませんでしょうか? (On Error があるのは、空行のためです。)とすでに書いてあったかと思いますが、配列にしても配列が空の場合は、エラーになりますので、それを避けるためです。 持ち込むデータが、何かわからない場合(この特定は、目視では分らないことがあります)、なかなかむつかしいのです。何であると、こちらで決めて掛かるわけにはいかないわけで、出力元を教えてもらうなどしてもらわないと、正確には出来ません。 コンマ区切り(CSV)なのか、タブ切りなのか、スペース区切りなのか、まだ他にも、バイナリタイプのものや、シーケンシャルファイルなど、それぞれに区切り方があります。それは、CSVは、今は、Excelの専売特許のようですが、どちらかというと、データベースソフトのためのものです。 #4 の KenKey_SPさんの 2005/11/2,東京支店,田中,"\123,456" の場合も、Line Input に変りませんが、Split関数の代わりに、サブルーチンで、切り分けて配列にします。私は、いままで、これを正規表現で切り分けてきましたが、Instr関数で切り分けることも可能です。 vbCR (\n) の場合は、経験したことがありませんので分りませんが、文書全体を、正規表現のループで切り分けることは可能だと思います。

booooob
質問者

お礼

ご返答いただきありがとうございます。 私の乏しい知識では理解できない部分もありますが、 これから疑問点を調べながら、いただいたアドバイスをモノにしていきたいと思います。 この度は誠にありがとうございました。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.4

#2 です。 余談ですが、、 Split 関数や Line Input を使って CSV データのフィールド分割 を行う場合は、次のようなデータの読み込みに失敗しますので、 ご注意を。 例1) 2005/11/2,東京支店,田中,"\123,456"    →2005/11/2  東京支店  田中  "\123  456"     ありがちですが、金額フィールドの桁区切りカンマとか。 例2) キャリッジ リターン (vbCr)を含むフィールドがある     データ    →1レコードがそのフィールドで複数のレコードに分割され     てしまいます。これが Line Input の特性です。     Excel でセル内改行のあるデータを CSV に書き出すと     このようなデータになります。 したがって、Line Input や Split 関数を使って CSV データを読み 込むコードを書く場合には、CSV ファイル内にこのようなデータが 含まれるかどうかを検証する必要があります。

booooob
質問者

お礼

例1は分かっておりましたが、例2は知りませんでした。 教えていただいて助かりました。 危うくトラブルに見舞われるところでした。 読み込ませたいデータを検証してから、Line Input を利用したいと思います。 貴重なアドバイスをありがとございます。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.2

こんにちは。KenKen_SP です。 Dir 関数の戻り値はファイル名だけで、パスが含まれません。 Sub 同階層フォルダ内のCSV読込_Click()         Dim fname    As String 'ファイル名   Dim pathname  As String 'パス名   Dim dat(1 To 4) As Variant '読み込んだデータ   Dim rr     As Long '対象行番号   Dim i      As Integer '列のオフセット   Dim j      As Integer 'ファイル識別番号のオフセット      '同階層フォルダ内のCSVファイルを参照   pathname = ThisWorkbook.Path   fname = Dir(pathname & "\*.csv", vbNormal)      'データを挿入する行番号   rr = 2      j = 0   '該当するファイルがある間   Do While fname <> ""     j = j + 1     'ファイルを開く     Open pathname & "\" & fname For Input As #j     'ファイルの終端まで     Do Until EOF(j)       'データを取得       Input #j, dat(1), dat(2), dat(3), dat(4)       '読み込んだデータをセルに出力       For i = 1 To 4         Cells(rr, i).Value = dat(i)       Next       '行番号を更新       rr = rr + 1     Loop     Close #j     'フォルダ内の次のファイルを検索     fname = Dir()   Loop End Sub

booooob
質問者

お礼

Dir 関数の戻り値はファイル名だけなのですね。 大変勉強になりました。 ご提示いただいたコードで、正常に動作するようになりました。 ありがとうございました。

  • wuyan
  • ベストアンサー率51% (183/352)
回答No.1

とりえず、j = 0 は Do ループの中ではなく外 (前) に出すこと

booooob
質問者

お礼

見落としていました。 ご指摘ありがとうございます。

関連するQ&A