02 June 2010

(VBScript) テキストファイル(CSV)の最終行のみを取り出す

VBScriptを用いて、テキストファイル(CSV形式)の最終行のデータのみを高速で取り出す方法を試行錯誤してみる

(1) 1行ずつ順番に読み込んで、最後の行まで到達する方法

Option Explicit On Error Resume Next Dim objFSO ' FileSystemObject Dim objFile ' ファイル読み込み用 Dim strTemp Const ForReading = 1, ForWriting = 2, ForAppending = 3 Dim tmStart, tmEnd ' 実行時間計測用 tmStart = Timer ' 開始時間 Set objFSO = CreateObject("Scripting.FileSystemObject") If Err.Number = 0 Then Set objFile = objFSO.OpenTextFile("f:\temp\test.csv", ForReading) If Err.Number = 0 Then ' 1行ずつEOFまで読み込む Do While objFile.AtEndOfStream <> True strTemp = objFile.ReadLine Loop objFile.Close Else strTemp = "読み込みエラー" End If Else strTemp = "ファイルが開けない" End If tmEnd = Timer ' 終了時間 tmEnd = tmEnd - tmStart ' 実行時間を得る MsgBox(strTemp + " : " + FormatNumber(tmEnd,10) + " sec")

(2)全行を一気に読み込み、Split関数で配列に切り分ける方法

Option Explicit On Error Resume Next Dim objFSO ' FileSystemObject Dim objFile ' ファイル読み込み用 Dim strAll ' ファイル全体を一旦読み込むバッファ Dim arrAll Dim strTemp Const ForReading = 1, ForWriting = 2, ForAppending = 3 Dim tmStart, tmEnd ' 実行時間計測用 tmStart = Timer ' 開始時間 Set objFSO = CreateObject("Scripting.FileSystemObject") If Err.Number = 0 Then Set objFile = objFSO.OpenTextFile("f:\temp\test.csv", ForReading) If Err.Number = 0 Then strAll = objFile.ReadAll ' ファイル全てをバッファに格納 objFile.Close arrAll = Split(strAll, vbCrLf) ' 配列に切り分けて格納 strTemp = arrAll(Ubound(arrAll)-1) ' 最終要素のみ取り出す Else strTemp = "読み込みエラー" End If Else strTemp = "ファイルが開けない" End If tmEnd = Timer ' 終了時間 tmEnd = tmEnd - tmStart ' 実行時間を得る MsgBox(strTemp + " : " + FormatNumber(tmEnd,10) + " sec")

655350行のデータで試してみたところ

(1)の場合、1.625秒
(2)の場合、2.172秒

ログデータを頻繁に読み込まないといけない場合、これではCPUに負荷を掛けてしまうので不適切なプログラムになってしまう。

で、考えたのが、決め打ちで「シーク」する方法。1行のデータが、明らかに32バイトに収まると仮定して…

Option Explicit On Error Resume Next Dim objFSO ' FileSystemObject Dim objFile ' ファイル読み込み用 Dim strAll ' ファイル全体を一旦読み込むバッファ Dim strLastPart Dim arrAll Dim strTemp Const ForReading = 1, ForWriting = 2, ForAppending = 3 Dim tmStart, tmEnd ' 実行時間計測用 tmStart = Timer ' 開始時間 Set objFSO = CreateObject("Scripting.FileSystemObject") If Err.Number = 0 Then Set objFile = objFSO.OpenTextFile("f:\temp\test.csv", ForReading) If Err.Number = 0 Then strAll = objFile.ReadAll ' ファイル全てをバッファに格納 objFile.Close strLastPart = Right(strAll, 32) ' バッファの後ろから32バイトを切り出す arrAll = Split(strLastPart, vbCrLf) strTemp = arrAll(Ubound(arrAll)-1) Else strTemp = "読み込みエラー" End If Else strTemp = "ファイルが開けない" End If tmEnd = Timer ' 終了時間 tmEnd = tmEnd - tmStart ' 実行時間を得る MsgBox(strTemp + " : " + FormatNumber(tmEnd,10) + " sec")

このようにすると、実行時間が 0.28秒。