概要
Excel VBAを用いてCSVファイルの行数を取得する際、多くの初心者が陥る罠が「全データをワークシートに読み込んでからCountプロパティを使う」という手法です。しかし、数万行から数十万行規模のCSVを扱う場合、この方法はメモリを大量に消費し、処理速度が著しく低下します。本記事では、VBAのファイルI/O機能(ADODBやFileSystemObject)を駆使し、CSVファイルをメモリに展開することなく、極めて高速に行数のみをカウントするテクニックを解説します。業務効率を劇的に向上させるための、プロフェッショナルな実装手法を学びましょう。
詳細解説:なぜ行数取得に工夫が必要なのか
CSVファイルをExcelで開く際、OpenメソッドやWorkbooks.Openを使用すると、Excelはすべてのセルを解析し、データ型を判定し、書式を適用します。これが「重い」原因です。特に数GBに達するような巨大なCSVファイルでは、Excelの限界行数(1,048,576行)を超えてしまう可能性があり、エラーやフリーズを引き起こします。
行数を知るだけであれば、ファイルの中身をすべてメモリにロードする必要はありません。テキストファイルとして「改行コード(LFまたはCRLF)」がいくつ存在するかを数えれば、それがそのまま行数になります。
最も高速な手法の一つが、ADO(ActiveX Data Objects)を使用する方法、あるいはFileSystemObject(FSO)でテキストストリームとして読み込む方法です。今回は、環境依存が少なく、大容量ファイルでも安定して動作するFSOを用いたアプローチを深く掘り下げます。
サンプルコード:FileSystemObjectを用いた高速カウント手法
以下のコードは、指定したCSVファイルの行数を、ファイルをすべて読み込まずにストリームとして走査し、高速に計算する関数です。
Option Explicit
' 参照設定不要で動作するFileSystemObjectを用いた行数カウント関数
Public Function GetCsvLineCount(ByVal filePath As String) As Long
Dim fso As Object
Dim ts As Object
Dim lineCount As Long
Set fso = CreateObject("Scripting.FileSystemObject")
' ファイルが存在するか確認
If Not fso.FileExists(filePath) Then
Err.Raise vbObjectError + 1000, , "ファイルが見つかりません: " & filePath
End If
' ファイルを読み取り専用で開く
Set ts = fso.OpenTextFile(filePath, 1, False)
lineCount = 0
' EOF(End Of File)に達するまで1行ずつ読み飛ばす
' 実際にはデータを変数に格納しないため、メモリ消費は最小限
Do While Not ts.AtEndOfStream
ts.SkipLine
lineCount = lineCount + 1
Loop
ts.Close
Set ts = Nothing
Set fso = Nothing
GetCsvLineCount = lineCount
End Function
' 呼び出し用メインプロシージャ
Public Sub Main()
Dim targetPath As String
Dim totalLines As Long
targetPath = "C:\Data\LargeSample.csv"
On Error Resume Next
totalLines = GetCsvLineCount(targetPath)
If Err.Number = 0 Then
MsgBox "対象ファイルの行数は " & totalLines & " 行です。", vbInformation
Else
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End If
On Error GoTo 0
End Sub
詳細解説:コードのポイント
上記のコードには、ベテランエンジニアが意識するいくつかの重要なポイントがあります。
1. SkipLineメソッドの活用:
通常、ReadLineメソッドで1行ずつ文字列を変数に代入すると、メモリの確保と解放が繰り返されます。一方、SkipLineはファイルポインタを次の行頭まで進めるだけで、メモリへのデータ転送を行いません。これが圧倒的な速度を生む鍵となります。
2. オブジェクトの解放:
Set ts = Nothing、Set fso = Nothingを確実に行うことで、メモリリークを防ぎます。特にループ処理の中で頻繁に呼び出す場合、この後始末を怠るとExcel全体のパフォーマンスが低下します。
3. エラーハンドリング:
外部ファイルを扱う以上、ファイルがロックされている、パスが間違っているといった例外は常に発生し得ます。Errオブジェクトを活用した堅牢なエラーハンドリングは、実務レベルのコードには不可欠です。
実務アドバイス:更なる高速化と注意点
もし、対象のCSVファイルが「数百万行」を超えるような超巨大データの場合、FSOのSkipLineでも時間がかかることがあります。その場合の代替案として、ADODB.Streamを使用する方法があります。
ADODB.Streamでファイルをバイナリとして読み込み、改行コードのバイト数(LF: 10、CRLF: 13, 10)を数える手法です。これはFSOよりもさらに高速ですが、文字コードの判定が複雑になるリスクがあります。実務では、「速度」と「安定性」のバランスを見て選定してください。
また、CSVファイル内の「引用符(”)」で囲まれた改行(データ内の改行)については、今回の行数カウントロジックでは「1行」としてカウントされます。厳密に「レコード数」を知りたい場合は、CSVの構文解析が必要になりますが、通常のログファイルやエクスポートデータであれば、上記の手法で十分正確に行数を把握可能です。
まとめ
Excel VBAでCSVの行数を取得する際、安易にワークシートへ取り込むのは禁物です。FileSystemObjectのSkipLineを活用すれば、メモリを圧迫することなく、巨大なファイルであっても軽快に行数を取得できます。
プロフェッショナルなVBA開発者を目指すなら、「いかにデータをロードせずに目的を達成するか」という視点が重要です。本記事で紹介したコードをベースに、皆さんの業務環境に合わせて最適化してみてください。確実な技術の積み重ねこそが、複雑なシステムを安定して運用するための唯一の道です。このテクニックをあなたの道具箱に加え、日々の自動化ツールをより洗練されたものへと進化させてください。
