【VBAリファレンス】VBAサンプル集CSVの読み込み方法(ジャグ配列)

スポンサーリンク

VBAにおけるCSV読み込みの最適解:ジャグ配列を活用した高速処理の実践

Excel VBAを用いた業務自動化において、外部データの取り込みは避けて通れないタスクです。特にCSVファイルは、システムのインターフェースとして最も一般的な形式ですが、標準的な「QueryTables」や「Openステートメントによる1行ずつの読み込み」は、データ量が増大するにつれて処理速度が著しく低下するという課題があります。

本記事では、メモリ上で完結する「ジャグ配列(配列の配列)」を活用し、数万行規模のデータを瞬時にメモリへ展開し、加工・出力するプロフェッショナルな手法を解説します。

ジャグ配列とは何か:なぜCSV処理に適しているのか

ジャグ配列(Jagged Array)とは、配列の中にさらに配列を格納する構造を指します。一般的な2次元配列(Array(x, y))は、全ての行が同じ列数を持つ必要があります。しかし、CSVデータは行によってデータ構造が異なる場合や、可変長のデータを取り扱う際に、2次元配列ではメモリの再定義(ReDim Preserve)が極めて非効率になるという欠点があります。

ジャグ配列を活用することで、以下のメリットが享受できます。

1. メモリ効率の向上:必要な分だけを動的に確保できるため、無駄なメモリ領域を占有しません。
2. 処理速度の劇的な改善:セルへ直接書き込む回数を最小限に抑え、メモリ上で全ての加工を完結させた後に一括でシートへ転記することが可能です。
3. 可読性と保守性:データ構造をオブジェクト指向に近い形で管理できるため、複雑なCSVのパース処理を論理的に整理できます。

CSVファイルをジャグ配列に格納する実装手順

CSVの読み込みにおいて最も重要なのは、「ファイルをバイナリとして一括で読み込み、メモリ上で分割する」というアプローチです。1行ずつ読み込むループは、ファイルI/Oのオーバーヘッドが大きく、実務レベルでは推奨されません。

以下に、実務でそのまま利用可能な、堅牢かつ高速なCSV読み込みコードを提示します。


Option Explicit

' CSVをジャグ配列に読み込み、シートへ書き出すメインプロシージャ
Public Sub ImportCSVToJaggedArray()
    Dim filePath As String
    Dim fileNum As Integer
    Dim fileContent As String
    Dim rowsData() As String
    Dim jaggedArray() As Variant
    Dim i As Long, j As Long
    
    filePath = Application.GetOpenFilename("CSVファイル (*.csv), *.csv")
    If filePath = "False" Then Exit Sub
    
    ' ファイルをバイナリモードで一括読み込み
    fileNum = FreeFile
    Open filePath For Binary Access Read As #fileNum
    fileContent = Space(LOF(fileNum))
    Get #fileNum, , fileContent
    Close #fileNum
    
    ' 行単位で分割
    rowsData = Split(fileContent, vbCrLf)
    
    ' ジャグ配列の初期化
    ReDim jaggedArray(UBound(rowsData))
    
    ' 各行をカンマで分割してジャグ配列に格納
    For i = LBound(rowsData) To UBound(rowsData)
        If Len(rowsData(i)) > 0 Then
            jaggedArray(i) = Split(rowsData(i), ",")
        End If
    Next i
    
    ' シートへの転記(サンプルとしてA1セルから出力)
    OutputToSheet jaggedArray
End Sub

' ジャグ配列をシートへ出力するプロシージャ
Private Sub OutputToSheet(ByRef dataArray() As Variant)
    Dim i As Long, j As Long
    Dim targetSheet As Worksheet
    Set targetSheet = ThisWorkbook.Sheets(1)
    
    Application.ScreenUpdating = False
    
    For i = LBound(dataArray) To UBound(dataArray)
        If IsArray(dataArray(i)) Then
            For j = LBound(dataArray(i)) To UBound(dataArray(i))
                targetSheet.Cells(i + 1, j + 1).Value = dataArray(i)(j)
            Next j
        End If
    Next i
    
    Application.ScreenUpdating = True
End Sub

詳細解説:コードの挙動とエンジニアリングの勘所

上記のコードにおいて、最も注目すべきは「Open For Binary」を用いたファイル読み込みです。VBAにおいて「Input #」や「Line Input #」を使うと、OSのファイルシステムを何度も呼び出すことになり、これがボトルネックとなります。バイナリモードで一度に変数(String型)へ読み込むことで、ディスクアクセスを1回に集約し、処理速度を数百倍に向上させることが可能です。

また、Split関数によって生成される配列は、Variant型の要素を持つ配列となります。これが「ジャグ配列」としての実体です。この構造により、例えば「ある行は3項目、次の行は5項目」といった不規則なCSVデータであっても、インデックスエラーを起こすことなく柔軟にメモリ上で扱えます。

実務アドバイス:大規模データとエラーハンドリング

実務の現場では、単に読み込むだけでなく、以下の点に留意する必要があります。

1. ダブルクォーテーションの処理:
CSV標準規格では、カンマを含むフィールドはダブルクォーテーションで囲まれます。上記の単純なSplit(data, “,”)では、これらを正しく分離できません。この場合、正規表現(VBScript.RegExp)を用いて、区切り文字を判定するロジックを組み込む必要があります。

2. 文字コードの罠:
日本の現場では、CSVが「Shift-JIS」ではなく「UTF-8(BOMなし)」で作成されていることが多々あります。その場合、上記コードでは文字化けが発生します。ADODB.Streamオブジェクトを使用して、文字コードを指定して読み込む手法を併用してください。

3. メモリ管理:
数百万行のデータを扱う場合、ジャグ配列は非常にメモリを消費します。不要になった段階で「Erase jaggedArray」を実行し、メモリを明示的に解放する習慣をつけてください。

4. 転記の最適化:
サンプルコードでは分かりやすさのために「Cells(i, j).Value」で転記していますが、実務では「配列をRangeに一括代入する」のが鉄則です。ジャグ配列から2次元配列へ変換する関数を作成し、`Range(“A1”).Resize(UBound(data, 1), UBound(data, 2)).Value = data` の形式で書き出すことで、処理時間はさらに短縮されます。

まとめ:VBAの限界を突破するデータ処理技術

VBAは、正しく設計すれば現代の業務システムにおいても十分なパフォーマンスを発揮します。ジャグ配列を用いたCSV処理は、単なるプログラミングテクニックではなく、メモリ管理とファイルI/Oの最適化という、計算機科学の基本に基づいたアプローチです。

「遅い」「フリーズする」といったVBAへの不満の多くは、単にコードの書き方が古いことに起因します。本稿で紹介したバイナリ読み込みとジャグ配列の活用を習得することで、あなたのVBA開発スキルは一段上のレベルへと引き上げられるはずです。

大規模なCSVデータを扱う際は、まずメモリ上でデータ構造をどう定義するかを設計し、その後にI/Oを最適化する。このエンジニアリングのプロセスを徹底することで、堅牢でメンテナンス性の高い業務自動化ツールを構築してください。VBAは、プロの手による設計を待っています。

タイトルとURLをコピーしました