皆さん、こんにちは!Excel VBA講師の〇〇です。日々の業務で、CSVファイルの扱いは避けて通れませんよね。大量のデータをインポートしたり、外部システムから受け取ったデータを加工したりする際に、「このCSVファイル、一体何行あるんだろう?」と疑問に思うことはありませんか?
CSVファイルの行数を知ることは、処理の進捗確認、データ件数の把握、あるいはエラーチェックなど、様々な場面で役立ちます。しかし、ファイルを開かずにVBAでその行数を取得するには、少し工夫が必要です。今回は、Excel VBAを使ってCSVファイルの行数を正確かつ効率的に取得する方法を、初心者の方にもわかりやすく解説していきます。
なぜCSVファイルの行数を知る必要があるのか?
まず、なぜCSVファイルの行数を知ることが重要なのか、具体的なシーンをいくつか見てみましょう。
* **データ件数の把握:** 外部システムから受け取ったデータが想定通りの件数になっているか確認する。
* **処理時間の予測:** 大量のデータを処理する前に、おおよその処理時間を把握する。
* **エラーチェック:** 異常に少ない行数や多すぎる行数から、データ異常を早期に発見する。
* **進捗管理:** 大規模なデータ処理において、全体の何%が完了したかなどを把握する。
* **メモリ管理:** 大量のデータをVBAで一度に読み込む際に、メモリ使用量を考慮する。
このように、CSVファイルの行数を知ることは、データ処理の安全性と効率性を高める上で非常に有効な手段なのです。
CSVファイルを「開かずに」行数を取得する難しさ
Excel VBAでCSVファイルを扱う場合、通常は `Workbooks.Open` メソッドを使ってExcelブックとして開くのが一般的です。しかし、この方法ではCSVファイルを開くという操作が発生するため、以下のデメリットがあります。
* **処理速度の低下:** ファイルを開くという処理自体に時間がかかります。特にファイルサイズが大きい場合、顕著な差が出ます。
* **メモリ使用量の増加:** CSVファイルをExcelブックとして開くと、その内容がメモリ上に展開されます。大量のデータを扱う場合、メモリ不足の原因となる可能性があります。
* **画面表示のちらつき:** Excelの画面上でファイルが開閉されるため、ユーザーによっては画面がちらつくように見えてしまい、操作感が悪くなることがあります。
* **一時的なファイルロック:** ファイルを開いている間は、他のプロセスからそのファイルを編集することができなくなる場合があります。
これらの理由から、単に行数を取得するだけであれば、CSVファイルを直接開かずに、より軽量な方法で処理したいと考えるのが自然です。
CSVファイルの行数を取得するVBAテクニック集
それでは、CSVファイルを直接開かずに、VBAでその行数を取得する具体的な方法をいくつかご紹介します。それぞれにメリット・デメリットがありますので、状況に応じて使い分けてみてください。
テクニック1:FileSystemObject を使ったテキストファイル読み込み
この方法は、COMオブジェクトである `FileSystemObject` を利用して、CSVファイルをテキストファイルとして扱い、1行ずつ読み込んでカウントする方法です。Excelのブックとして開かないため、非常に高速かつメモリ効率が良いのが特徴です。
**メリット:**
* 高速でメモリ効率が良い。
* Excelの画面操作を伴わない。
* 比較的シンプルで理解しやすい。
**デメリット:**
* CSVファイルの内容を直接読み込むため、ファイルサイズが大きいと処理に時間がかかる場合がある(ただし、Excelを開くよりは断然速い)。
* 文字コードによっては、正しく読み込めない可能性がある(後述の注意点参照)。
**コード例:**
Function GetCsvLineCount_FileSystemObject(filePath As String) As Long
Dim fso As Object
Dim ts As Object
Dim lineCount As Long
On Error GoTo ErrorHandler
‘ FileSystemObjectを作成
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ ファイルが存在するかチェック
If Not fso.FileExists(filePath) Then
MsgBox “指定されたファイルが見つかりません。”, vbExclamation
GetCsvLineCount_FileSystemObject = -1 ‘ エラーを示す値
Exit Function
End If
‘ テキストストリームを開く (ForReading = 1)
Set ts = fso.OpenTextFile(filePath, 1)
lineCount = 0
‘ ファイルの終端まで1行ずつ読み込む
Do While Not ts.AtEndOfStream
ts.ReadLine
lineCount = lineCount + 1
Loop
‘ テキストストリームを閉じる
ts.Close
‘ 結果を返す
GetCsvLineCount_FileSystemObject = lineCount
‘ オブジェクトを解放
Set ts = Nothing
Set fso = Nothing
Exit Function
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
GetCsvLineCount_FileSystemObject = -1 ‘ エラーを示す値
If Not ts Is Nothing Then
If ts.AtEndOfStream = False Then ts.Close ‘ エラー時もクローズを試みる
End If
Set ts = Nothing
Set fso = Nothing
End Function
‘ — 呼び出し例 —
Sub Test_GetCsvLineCount_FileSystemObject()
Dim csvPath As String
Dim lines As Long
‘ ★★★ 実際のCSVファイルのパスに変更してください ★★★
csvPath = ThisWorkbook.Path & “\sample.csv” ‘ 例: VBAコードと同じフォルダのsample.csv
lines = GetCsvLineCount_FileSystemObject(csvPath)
If lines >= 0 Then
MsgBox “CSVファイルの行数: ” & lines & ” 行”
Else
MsgBox “行数の取得に失敗しました。”
End If
End Sub
**コードの解説:**
1. `CreateObject(“Scripting.FileSystemObject”)`: FileSystemObjectを作成します。これにより、ファイル操作が可能になります。
2. `fso.FileExists(filePath)`: 指定されたパスにファイルが存在するかどうかを確認します。
3. `fso.OpenTextFile(filePath, 1)`: ファイルを読み込みモード(`1`)で開きます。
4. `Do While Not ts.AtEndOfStream`: ファイルの終端に達するまでループします。
5. `ts.ReadLine`: ファイルから1行読み込みます。この行の内容は使用しませんが、読み込むことでポインタが次の行に進みます。
6. `lineCount = lineCount + 1`: 1行読み込むたびにカウンターを増やします。
7. `ts.Close`: ファイルを閉じます。
8. `Set ts = Nothing`, `Set fso = Nothing`: オブジェクトを解放します。
**文字コードに関する注意点:**
`FileSystemObject` は、Windowsのデフォルトのテキストエンコーディング(通常はANSI)でファイルを読み込もうとします。UTF-8などの異なるエンコーディングのCSVファイルを扱う場合、文字化けが発生したり、正しく行数がカウントできなかったりする可能性があります。
もしUTF-8などのファイルを扱う必要がある場合は、`OpenTextFile` メソッドの第3引数(`Format`)でエンコーディングを指定するか、`ADODB.Stream` オブジェクトを使用するなどの工夫が必要です。
#### テクニック2:ADODB.Stream を使ったテキストファイル読み込み
`FileSystemObject` よりもさらに柔軟に文字コードを指定できるのが、`ADODB.Stream` オブジェクトを使用する方法です。データベース接続などでよく使われるオブジェクトですが、テキストファイルの読み書きにも強力な機能を持っています。
**メリット:**
* 文字コード(UTF-8, Shift_JISなど)を明示的に指定できるため、文字化けの問題を回避しやすい。
* `FileSystemObject` と同様に、Excelを開かずに高速に処理できる。
**デメリット:**
* `FileSystemObject` よりも少しコードが複雑になる。
* 参照設定が必要になる場合がある(通常は不要ですが、環境によっては `Microsoft ActiveX Data Objects x.x Library` を参照設定に追加すると安定します)。
**コード例:**
Function GetCsvLineCount_ADODB(filePath As String, Optional encoding As String = “UTF-8”) As Long
Dim stream As Object
Dim lineCount As Long
Dim line As String
On Error GoTo ErrorHandler
‘ ADODB.Streamオブジェクトを作成
Set stream = CreateObject(“ADODB.Stream”)
‘ ストリームのプロパティを設定
With stream
.Charset = encoding ‘ 指定されたエンコーディングを設定
.Open ‘ ストリームを開く
‘ ファイルが存在するかチェック (Openメソッドでエラーになる場合もあるが、明示的にチェック)
If Dir(filePath) = “” Then
MsgBox “指定されたファイルが見つかりません。”, vbExclamation
GetCsvLineCount_ADODB = -1 ‘ エラーを示す値
Exit Function
End If
‘ ファイルをバイナリモードで開く(文字コード指定のため)
.LoadFromFile filePath
‘ ファイルの先頭に移動
.Position = 0
lineCount = 0
‘ ファイルの終端まで1行ずつ読み込む
Do While Not .EOS ‘ .EOSはEnd Of Streamの略
line = .ReadLine
lineCount = lineCount + 1
Loop
End With
‘ ストリームを閉じる
stream.Close
‘ 結果を返す
GetCsvLineCount_ADODB = lineCount
‘ オブジェクトを解放
Set stream = Nothing
Exit Function
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
GetCsvLineCount_ADODB = -1 ‘ エラーを示す値
If Not stream Is Nothing Then
If stream.State = 1 Then ‘ adStateOpen = 1
stream.Close ‘ エラー時もクローズを試みる
End If
End If
Set stream = Nothing
End Function
‘ — 呼び出し例 —
Sub Test_GetCsvLineCount_ADODB()
Dim csvPath As String
Dim lines As Long
‘ ★★★ 実際のCSVファイルのパスに変更してください ★★★
csvPath = ThisWorkbook.Path & “\sample_utf8.csv” ‘ 例: UTF-8エンコーディングのCSV
‘ UTF-8の場合
lines = GetCsvLineCount_ADODB(csvPath, “UTF-8”)
If lines >= 0 Then
MsgBox “CSVファイル (UTF-8) の行数: ” & lines & ” 行”
Else
MsgBox “行数の取得に失敗しました。”
End If
‘ Shift_JISの場合 (必要に応じてエンコーディングを変更)
‘ csvPath = ThisWorkbook.Path & “\sample_sjis.csv”
‘ lines = GetCsvLineCount_ADODB(csvPath, “Shift_JIS”)
‘ If lines >= 0 Then
‘ MsgBox “CSVファイル (Shift_JIS) の行数: ” & lines & ” 行”
‘ Else
‘ MsgBox “行数の取得に失敗しました。”
‘ End If
End Sub
**コードの解説:**
1. `CreateObject(“ADODB.Stream”)`: ADODB.Streamオブジェクトを作成します。
2. `.Charset = encoding`: ここで文字コードを指定します。`”UTF-8″` や `”Shift_JIS”` などを指定できます。
3. `.Open`: ストリームを開きます。
4. `Dir(filePath) = “”`: ファイルの存在チェックを行っています。
5. `.LoadFromFile filePath`: 指定されたファイルをストリームに読み込みます。
6. `.Position = 0`: ファイルの先頭にポインタを移動させます。
7. `Do While Not .EOS`: ファイルの終端 (`.EOS` – End Of Stream) に達するまでループします。
8. `.ReadLine`: 1行読み込みます。
9. `lineCount = lineCount + 1`: カウンターを増やします。
10. `.Close`: ストリームを閉じます。
この方法は、文字コードの問題に悩まされることなく、確実にCSVファイルの行数を取得したい場合に非常に有効です。
テクニック3:Excelの機能(開く)を利用する(非推奨だが参考までに)
前述の通り、この方法は推奨しませんが、最も直感的で、VBA初心者の方が最初に思いつく方法かもしれません。参考までにコードを示します。
**メリット:**
* VBAの知識があまりなくても、比較的簡単に実装できる。
* CSVファイルの内容をExcelシートとして扱えるため、行数だけでなく他の情報も取得しやすい。
**デメリット:**
* **処理速度が遅い。**
* **メモリ使用量が多い。**
* 画面表示のちらつきが発生する。
* ファイルを開いている間、他のプロセスから編集できなくなる可能性がある。
**コード例:**
Function GetCsvLineCount_OpenWorkbook(filePath As String) As Long
Dim wb As Workbook
Dim lineCount As Long
On Error GoTo ErrorHandler
‘ CSVファイルを開く (TextFilePlatform:=42 は自動判別、Delimiter:=1 はタブ区切り、False は開いた後非表示にしない)
‘ Excel 2013以降では、OpenTextメソッドが推奨されますが、ここでは汎用的なWorkbooks.Openを使用します。
‘ より新しいバージョンでは、OpenTextメソッドの方が柔軟性があります。
Set wb = Workbooks.Open(Filename:=filePath, _
Format:=xlCSV, _
Delimiter:=”,”, _
Origin:=xlMSDOS, _
Scroll:=True, _
Notify:=False)
‘ ワークシートの最終行を取得
‘ CSVファイルにヘッダー行がある場合、それを考慮して1を引くなどの調整が必要な場合があります。
‘ ここでは単純に最終行数を取得します。
If wb.Worksheets.Count > 0 Then
lineCount = wb.Worksheets(1).Cells.SpecialCells(xlCellTypeLastCell).Row
Else
lineCount = 0 ‘ シートがない場合
End If
‘ ブックを閉じる(変更は保存しない)
wb.Close SaveChanges:=False
‘ 結果を返す
GetCsvLineCount_OpenWorkbook = lineCount
‘ オブジェクトを解放
Set wb = Nothing
Exit Function
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
GetCsvLineCount_OpenWorkbook = -1 ‘ エラーを示す値
If Not wb Is Nothing Then
wb.Close SaveChanges:=False ‘ エラー時もクローズを試みる
End If
Set wb = Nothing
End Function
‘ — 呼び出し例 —
Sub Test_GetCsvLineCount_OpenWorkbook()
Dim csvPath As String
Dim lines As Long
‘ ★★★ 実際のCSVファイルのパスに変更してください ★★★
csvPath = ThisWorkbook.Path & “\sample.csv”
lines = GetCsvLineCount_OpenWorkbook(csvPath)
If lines >= 0 Then
MsgBox “CSVファイルの行数 (Excelを開いた場合): ” & lines & ” 行”
Else
MsgBox “行数の取得に失敗しました。”
End If
End Sub
**コードの解説:**
1. `Workbooks.Open(…)`: CSVファイルをExcelブックとして開きます。`Format:=xlCSV` や `Delimiter:=”,”` など、CSVファイルの種類に応じてパラメータを調整する必要があります。
2. `wb.Worksheets(1).Cells.SpecialCells(xlCellTypeLastCell).Row`: 開いたワークブックの最初のシートの最終行を取得します。`xlCellTypeLastCell` は、データが入っている最も右下にあるセルの行番号を返します。
3. `wb.Close SaveChanges:=False`: ファイルを保存せずに閉じます。
**注意点:**
この方法で取得できる行数は、ExcelがCSVファイルをどのように解釈したかに依存します。例えば、空行が多い場合や、データが途中で途切れている場合など、CSVファイル自体の物理的な行数と一致しないことがあります。また、`xlCellTypeLastCell` は、過去にデータが入っていたセルも考慮するため、必ずしも現在データが入っている最終行を正確に表すとは限りません。
どのテクニックを選ぶべきか?
* **最も推奨されるのは、`ADODB.Stream` を使う方法です。** 文字コードの指定ができ、Excelを開かないため高速かつメモリ効率が良いからです。
* **次に推奨されるのは、`FileSystemObject` を使う方法です。** コードが比較的シンプルで、多くのケースで問題なく動作します。UTF-8などの特殊な文字コードを扱わないのであれば、こちらでも十分です。
* **`Workbooks.Open` を使う方法は、行数取得だけが目的なら避けるべきです。** 処理速度とリソース消費の観点から、現実的ではありません。
CSVファイルの行数を取得する際の注意点
* **ヘッダー行の扱い:** CSVファイルには、データの内容を示すヘッダー行が含まれていることがよくあります。上記のコードで取得できる行数は、ヘッダー行も含めた総行数です。もしデータ行数のみを知りたい場合は、取得した行数から1を引くなどの処理を追加してください。
* **空行の扱い:** CSVファイルには、意図的に、あるいはデータのエクスポート設定によって空行が含まれることがあります。上記のコード(特に `FileSystemObject` や `ADODB.Stream` を使う方法)では、空行も1行としてカウントされます。もし空行を除外したい場合は、読み込んだ行が空かどうかを判定する処理を追加する必要があります。
* **文字コード:** 前述の通り、CSVファイルの文字コードは様々です。UTF-8、Shift_JIS、EUC-JPなどが一般的です。`FileSystemObject` はデフォルトでANSIとして扱おうとしますが、`ADODB.Stream` なら明示的に指定できます。文字化けや誤った行数取得を防ぐために、ファイルの文字コードを把握しておくか、`ADODB.Stream` のような柔軟な方法を使用しましょう。
* **ファイルパスの指定:** VBAコードからCSVファイルを正しく参照できるように、ファイルパスは正確に指定してください。相対パス(例: `ThisWorkbook.Path & “\sample.csv”`)や絶対パス(例: `”C:\Data\sample.csv”`)を使用します。
まとめ
今回は、Excel VBAを使ってCSVファイルの行数を取得するいくつかの方法をご紹介しました。
* **`FileSystemObject`**
* **`ADODB.Stream`**
* **`Workbooks.Open` (非推奨)**
単に行数を取得したいだけであれば、Excelのブックとして開くのは避け、`FileSystemObject` や `ADODB.Stream` を利用するのが賢明です。特に `ADODB.Stream` は、文字コードの指定も可能で、最も汎用的かつ効率的な方法と言えるでしょう。
これらのテクニックをマスターすれば、CSVファイルのデータ処理がよりスムーズかつ安全になります。ぜひ、皆さんのVBA開発に役立ててください。
もし、特定のCSVファイルでうまくいかない、といったご質問がありましたら、お気軽にコメントくださいね!次回のブログもお楽しみに!
