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秒。