(1)基幹システム等から対象のデータを1ファイルでドカッと落としてきてその中で処理を行うような場合と、
(2)対象となる多数のCSVファイルがあって、各ファイルの中の該当するデータを抜き出したり集計したりする場合などがあると思います。
今回は後者の方です。
方針はいろんな立て方があると思います。
エクセルで処理をするので、各CSVをワークシートに読み込んで、一つの大きな表に結合して集計するんでも良いんです。
でも、セルの読み書きって時間がかかるので、それなら、CSVを配列に直接読み込んで集計すれば良いと思うんです。
まあ、そうなっちゃうとエクセルで処理してることになるのかどうかはちょっと疑問ではありますが。
で、多数のファイルを処理する場合、リストと照らし合わせてファイルの有無のチェックをするよりは、対象ファイルを一つのフォルダに入れて、それをリスト化して片っ端に処理した方が良いように思います。
フォルダ内のファイルのフルパスを配列に読み込む
やってると、buff=Dir(hoge) Do While buff<>"" ~ buff=Dir() Loop の間に処理を書くと、ファイルの読み込みがうまくいかなくなったりしたので、一旦対象ファイルを配列に読み込むことにしました。
ここでは拡張子指定にしてるけど、ファイル名に含まれる文字列で指定する等々簡単に書き直せるので、サンプルとしてはこんなので良いように思います。
'================================================' Function FullNamesIntoArrayByExtension( _ ByVal strFolder As String, _ ByVal strExtension As String _ ) As Variant ' --------------------------------------------- ' ' フォルダ内指定した拡張子の全ファイルの' ' フルパスを配列に読込む' ' 指定した拡張子のファイルが無い場合は' ' Ubound(取得した配列) = -1 を返す' '================================================' Dim strFullName As String Dim i As Long Dim buff As Variant Dim arrFiles() As String i = 0 strFullName = strFolder & "\" & "*." & strExtension '" buff = Dir(strFullName) Do While buff <> "" ReDim Preserve arrFiles(i) arrFiles(i) = strFolder & "\" & buff '" i = i + 1 buff = Dir() Loop If (Not arrFiles) = -1 Then ReDim arrFiles(-1 To -1) FullNamesIntoArrayByExtension = arrFiles Else FullNamesIntoArrayByExtension = arrFiles End If End Function
CSVファイルを配列に読込む
tetsuさんのブログですごく詳しく調べてあったので、参考にして、バイナリで読み込んで配列を戻す関数を書いてみました。
CSVファイルを配列に読込む関数
'========================================' Function TextIntoArray( _ ByVal pFilePath As String _ ) As Variant ' -------------------------------------- ' ' CSVファイルを配列に読込む' ' エラーが起きた場合は' ' Ubound(取得した配列) = -1 を返す' '========================================' Dim lFileNo As Long Dim buff As String Dim bBuff() As Byte Dim arrBuff Dim i As Long Dim j As Long Dim lItemCnt As Long Dim arrItem Dim arrData() ReDim arrData(-1 To -1) TextIntoArray = arrData On Error GoTo AbEnd lFileNo = FreeFile Open pFilePath For Binary As #lFileNo ReDim bBuff(LOF(lFileNo)) Get #lFileNo, , bBuff Close #lFileNo buff = StrConv(bBuff(), vbUnicode) arrBuff = Split(buff, vbCrLf) lItemCnt = UBound(Split(arrBuff(0), ",")) ReDim arrData(UBound(arrBuff), lItemCnt) For i = LBound(arrBuff) To UBound(arrBuff) arrItem = Split(arrBuff(i), ",") For j = LBound(arrItem) To UBound(arrItem) arrData(i, j) = arrItem(j) Next j Next i TextIntoArray = arrData Exit Function AbEnd: ReDim arrData(-1 To -1) TextIntoArray = arrData End Function
100,000のCSVファイルを集計してみる
このようなCSVファイルで、フラグ列に「S」が立っている行の2列目の値を10万ファイル分合計してみました。
テストなのでファイル名が違うだけで各ファイル内容は同じです。
10万ファイルで350秒くらい。1000ファイルくらいなら3秒程度で終わるので、割と使えると思います。
テストで使用したコード
Sub 十万ファイルの集計() Dim arrFiles, sFile Dim sFolder As String Dim arrData Dim i As Long Dim fSum As Single Dim StartTime, EndTime StartTime = Timer sFolder = "C:\Users\user\Desktop\集計テスト" arrFiles = FullNamesIntoArrayByExtension(sFolder, "csv") If UBound(arrFiles) = -1 Then Exit Sub For Each sFile In arrFiles arrData = TextIntoArray(sFile) 'CSVのFlag列の値が"S"の行のフィールド1列(2列目)の値を集計する' For i = LBound(arrData, 1) To UBound(arrData, 1) If arrData(i, 0) = "S" Then fSum = fSum + arrData(i, 1) End If Next i Next sFile EndTime = Timer MsgBox "合計値は" & Format(fSum, "#,###") & vbNewLine & _ "所要時間(秒):" & EndTime - StartTime End Sub
0 件のコメント:
コメントを投稿