- 締切済み
VBA 複数ファイルを読み込んで、抽出
VBA初心者です。どうぞよろしくお願いいたします。 <やりたいこと> 同じフォルダにある複数ファイル(logファイル)を順番に読み込み、 特定の文字が含まれている行だけを、別ファイル(sum.csv)に保存していきたい。 ファイルが多数あるため、VBAで処理できればと思っています。 急いでおり、今回は丸投げになりますが、どなたかコードを教えていただけますと 非常に助かります。 コードを見て、勉強させていただきます。 どうかよろしくお願いいたします。
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- keithin
- ベストアンサー率66% (5278/7941)
ありゃ,前に引っかかったのと同じですね。 修正: sub macro3() : loadlogfile2 mypath & myfile, myout : end sub 失礼しました。
- keithin
- ベストアンサー率66% (5278/7941)
ほとんどそのまま流用してみると sub macro3() dim myPath as string dim myFile as string dim myOut as string mypath = thisworkbook.path & "\" myfile = dir(mypath & "*.*log") open mypath & "sum.csv" for output as #1 close #1 myout = mypath & "sum.csv" do until myfile = "" loadlogfile2 myfile, myout myfile = dir() loop end sub Sub loadLogFile2(ByRef fileName As Variant, outName as variant) Dim rowNo As Integer Dim readString As String Dim st As Object Set st = CreateObject("ADODB.Stream") 'ADODB.Stream生成 st.Type = 2 'オブジェクトに保存するデータの種類を文字列型に指定する st.Charset = "utf-8" '文字コード(Shift_JIS, Unicodeなど) st.LineSeparator = 10 '改行LF(10) st.Open 'Streamのオープン st.LoadFromFile (fileName) 'ファイル読み込み open outname for append as #1 rowNo = 5 Do While Not st.EOS ' rowNo = rowNo + 1 readString = st.ReadText(-2) 'テキストを1行読み込む。 ' Cells(rowNo, 2).Value = readString '読み込んだ文字列をセルにセットする if instr(readstring, "特定の文字列") > 0 then print #1, readstring Loop close #1 st.Close 'Streamのクローズ Set st = Nothing End Sub
補足
ご回答ありがとうございます。本当にここまでおつきあいいただき恐縮です。 いただいたコードですが、下記のコード部分で「ファイルを開けませんでした」という エラーがでました。fileNameには、ちゃんとフォルダ内のファイル名が入っています。 st.LoadFromFile (fileName) 'ファイル読み込み ←ここでエラー 長々ととおつきあいいだだき恐縮ですが、 おわかりになりましたら、教えてください。 宜しくお願いいたします。
- keithin
- ベストアンサー率66% (5278/7941)
>本当のlogファイル(多いものは80,000KB位あります。) 今のマクロだと,その4分の1ぐらいのサイズが仕様的な限度ですね。 実用的にはもっと小さくしないと使えないと思います。 手っ取り早い対処法としては「改行コードの違いで全体を一度に読み込んでしまう」のが原因なので,テキストエディタ等で改行コードを標準ウィンドウズテキストのvbcrlfに置換(改行コードを変換して保存)してやれば,最初のマクロで(一行ずつ読みながら)問題なく処理することはできます。 たとえばTeraPadなど。 http://www5.ocn.ne.jp/~m-shin/other/terapad-return.html
補足
ご回答いただきありがとうございます! ログファイルは大量にあるので、1ファイルごとテキストエディタで変更することはとても大変な事情があります。なにかプログラムで対応できないかと調べてみたら、 ADODB.Streamというのを使うとできるように思えたのですが、自分ではコードが かけません もしお願いできるのであれば、ADODB.Streamを使ったコードを教えていただけないでしょうか。 http://www.hiihah.info/index.php?Excel%EF%BC%9AVBA%EF%BC%9AUTF-8%EF%BC%8FLF%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80 お願できれば、大変助かります。
- keithin
- ベストアンサー率66% (5278/7941)
>logファイルのデータを、改行のない、1行と判断している 実際にステップ実行してみてそのように動作しているのでしたら,そのlogファイルの「改行コード」が,ウィンドウズテキストファイルの標準改行コードとは異なっているのが原因です。 具体的に何が改行コードとして利用されているのか,あなたのlogファイルの実際の構造をご自分で把握してください。 例:vblfが改行コードだった場合 sub macro2() dim myPath as string dim myFile as string dim buf as string dim a as variant dim ax as variant mypath = thisworkbook.path & "\" myfile = dir(mypath & "*.*log") open mypath & "sum.csv" for output as #1 do until myfile = "" open mypath & myfile for input as #2 do until eof(2) line input #2, buf a = split(buf, vblf) ’他にvbcrとかで試す for each ax in a if instr(ax, "特定の文字列") > 0 then print #1, ax next loop close #2 myfile = dir() loop close #1 end sub
補足
ありがとうございます!思い通りの動きになりました。 ただ、 動きの検証用のファイルはファイル容量が小さかったので、問題なかったのですが、 本当のlogファイル(多いものは80,000KB位あります。)を3ファイル、フォルダにいれて、プログラムを動かしたところ、line input #2, bufのところで、応答無しに なってしまいました。強制的にファイルを閉じる時に、「文字列領域が不足」と出ていました。 ファイルの容量が大きすぎるということでしょうか?
- keithin
- ベストアンサー率66% (5278/7941)
>最初のコードに戻して、下記のようにしたのですが、やはり、open myfile for input as #2 の部分で、「ファイルが見つかりません」とでて止まります。 とりあえず Sub macro1() Dim myPath As String Dim myFile As String Dim buf As String myPath = ThisWorkbook.Path & "\" myFile = Dir(myPath & "*.*log") ’←ここだけ変えました。 Open myPath & "sum.csv" For Output As #1 Do Until myFile = "" ’←ここで「g002.httpd-access_log」が見えてるなら Open mypath & myFile For Input As #2 'ここも変更する Do Until EOF(2) Line Input #2, buf If InStr(buf, "特定の文字列") > 0 Then Print #1, buf Loop Close #2 myFile = Dir() Loop Close #1 End Sub スミマセン、 >今度は、myfileの中身が空になってしまいました。 のご説明と >Do Until myFile = "" のmyfileには、ちゃんとlogのファイル名「g002.httpd-access_log」が見えました。 のご説明が矛盾します。 デバッグしてみるとmyfileの中身は「空ではなかった」という事ですから、「今度は空になってしまいました」はどういうマクロのどういう状況でそういうご判断になったのか判らず、どこが間違えているのか絞れません。
補足
説明が悪く申し訳ありませんでした。 <矛盾点についてのお答え> 最初にいただいたコード myfile = dir(mypath & "*.log")・・・・open myfile for input as #2 では、Do Until myFile = "" の中身にファイル名が見えた。 myfile = dir("*.*_log")・・・・open mypath & myfile for input as #2 と変更しましたら、Do Until myFile = "" の中身が空になった。 最後にいただいたコード myFile = Dir(myPath & "*.*log") ・・・Open mypath & myFile For Input As #2では、Do Until myFile = "" の中身にファイル名が見えました。 -------------------------------------- <新たな問題> 最後にいただいたコードで、ためしてみたところ、時間は結構かかりましたが、 コードは最後まで動きました。 しかし、sum.csv の中身をみると、logファイルの中身がすべてそのまま転記されていて、 抽出が行われていませんでした。 logファイルのデータを極端に少なくして、プログラムの動きを見たところ、 Line Input #2, buf If~を、1つのlogファイルにつき1回しかしていないようでした。 logファイルのデータを、改行のない、1行と判断しているのかなと思いましたが、 どうしたらよいでしょうか? 本当にお手数おかけして申し訳ございませんが、 教えていただけますと助かります。 どうぞよろしくお願いいたします。
- keithin
- ベストアンサー率66% (5278/7941)
>「ファイルが見つかりません」とでて止まります。 はて、とりあえず丁寧に myfile = dir(*.*_log) : open mypath & myfile for input as #2 としてみます。
補足
ご回答いただきありがとうございます! ご指示のとおり、変更したのですが、今度は、myfileの中身が空になってしまいました。 ※myfile = dir(*.*_log)の部分は、エラーになったので、myfile = dir("*.*_log")と 書き換えて試してみました。 最初のコードに戻して、下記のようにしたのですが、やはり、open myfile for input as #2 の部分で、「ファイルが見つかりません」とでて止まります。 コードを1行づつ動かして、myfile の中身をみると、 Do Until myFile = "" のmyfileには、ちゃんとlogのファイル名「g002.httpd-access_log」が見えました。 お手数かけてすみません。どうしたら、よいか教えていただけますと助かります。 Sub macro1() Dim myPath As String Dim myFile As String Dim buf As String myPath = ThisWorkbook.Path & "\" myFile = Dir(myPath & "*.*log") ←ここだけ変えました。 Open myPath & "sum.csv" For Output As #1 Do Until myFile = "" Open myFile For Input As #2 Do Until EOF(2) Line Input #2, buf If InStr(buf, "特定の文字列") > 0 Then Print #1, buf Loop Close #2 myFile = Dir() Loop Close #1 End Sub
- keithin
- ベストアンサー率66% (5278/7941)
sub macro1() dim myPath as string dim myFile as string dim buf as string mypath = thisworkbook.path & "\" myfile = dir(mypath & "*.log") open mypath & "sum.csv" for output as #1 do until myfile = "" open myfile for input as #2 do until eof(2) line input #2, buf if instr(buf, "特定の文字列") > 0 then print #1, buf loop close #2 myfile = dir() loop close #1 end sub ブックをlogファイルと同じフォルダに放り込んでからマクロを実行する。
補足
keithin さん ご回答いただきありがとうございます! 教えていただいたコードで試してみたのですが、 open myfile for input as #2 の部分で、「ファイルが見つかりません」とでて止まります。 下記の部分を変更しています。これが原因でしょうか? ※ログファイルのファイル名が、201505g0002.httpd-access_log のような形なので、 *.log →*_log に変更。 お手数おかけいたしますが、教えていただきますと非常にありがたいです。 どうぞよろしくお願いいたします。
補足
本当にありがとうございます。思い通りの動きになりました! 図々しくも、さらにお伺いしたいことがあります。もし可能であれば教えてください。 今のコードは、解凍したいファイルと、プログラムが同じフォルダに入っていますが、 実際は、解凍したいファイルの入っているフォルダも複数あります。 できれば、下記のようにしたいのです。 logというフォルダの直下にプログラムをおく。 logフォルダの中の複数フォルダ内の複数ファイル(解凍対象)の特定文字の入っている行を、logフォルダ直下のsum.csvに書き込む。 log¥program.xlsx log¥sum.csv log¥201501¥g002.httpd-access_log ←解凍対象 ¥g003.httpd-access_log log¥201502¥g010.httpd-access_log ¥g011.httpd-access_log できましたら、ご回答いただけますと有り難いです。