巨大なCSVとの格闘に終止符を。VB.NETで実現する「爆速・堅牢」なファイル処理術
こんにちは。現場で長年、数ギガバイトのログデータやレガシーな取引データをさばいてきたエンジニアです。
「CSV読み込み」……一見簡単そうに見えますよね。しかし、実務の世界ではそう甘くありません。「Shift_JISなのかUTF-8なのか不明」「途中に不正なカンマがある」「ファイルサイズが数GBあってメモリがパンクする」。こうした現実に直面した時、ただ`StreamReader`で回すだけでは限界が来ます。
今日は、VB.NETの標準機能である`TextFieldParser`を使い、「文字コード自動判定」と「メモリ効率を極限まで高めた読み込み」を両立させる、プロの定石を伝授します。
—
1. なぜ「TextFieldParser」なのか?
`TextFieldParser`は、VB.NETが持つ特権的なクラスです。何が凄いかというと、「区切り文字」や「囲み文字(ダブルクォーテーションで囲まれたデータ)」のパースをOS任せにできる点です。
自前で`String.Split`を使うのはやめましょう。CSV内の`”東京都,千代田区”`のようなカンマを含むデータで、即座に論理崩壊を起こしますから。
—
2. 実践:文字コード判定と高速読み込みの融合
実務では「UTF-8 BOMなし」や「Shift_JIS」が混在します。これらを読み込み前に判定し、`TextFieldParser`へ流し込むのが正解です。
実装コード例
Imports Microsoft.VisualBasic.FileIO
Imports System.IO
Imports System.Text
Public Sub ProcessLargeCsv(filePath As String)
‘ 1. 文字コードを自動判定してStreamReaderを生成
‘ ※Encoding.Defaultではなく、BOM有無を考慮した判定が重要
Dim encoding As Encoding = DetectEncoding(filePath)
Using reader As New TextFieldParser(filePath, encoding)
‘ CSV形式であることを指定
reader.TextFieldType = FieldType.Delimited
reader.SetDelimiters(“,”)
reader.HasFieldsEnclosedInQuotes = True ‘ ダブルクォーテーション対策
‘ 2. 1行ずつ読み込む(全データをメモリに乗せないのが重要!)
While Not reader.EndOfData
Try
Dim fields As String() = reader.ReadFields()
‘ ここで各列の処理を行う
‘ ProcessRecord(fields)
Catch ex As MalformedLineException
‘ 壊れた行をスキップしてログ出力する等の堅牢性を持たせる
Console.WriteLine($”不正な行をスキップ: {ex.Message}”)
End Try
End While
End Using
End Sub
‘ 文字コード判定の簡易ロジック
Private Function DetectEncoding(path As String) As Encoding
‘ ※簡易的な例ですが、実務ではUde.NetStandardなどのライブラリ推奨
‘ 今回はUTF-8(BOMあり)かShift_JISかを判定する定石
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Dim bom(2) As Byte
fs.Read(bom, 0, 3)
If bom(0) = &HEF AndAlso bom(1) = &HBB AndAlso bom(2) = &HBF Then
Return Encoding.UTF8
End If
End Using
Return Encoding.GetEncoding(“Shift_JIS”)
End Function
—
3. 現場で生き残るための「3つの極意」
① 全データをメモリに読み込まない(ストリーミング)
`File.ReadAllLines`は絶対NGです。1GBのファイルを読み込めば、メモリも1GB以上消費し、アプリは即座にフリーズします。上記の通り、`While Not reader.EndOfData`を使って「一行ずつ処理」するのが鉄則です。
② 例外処理で止まらない
巨大CSVには、必ずと言っていいほど「ゴミデータ」が紛れています。`MalformedLineException`をキャッチして「どの行がダメだったか」をログに書き出し、処理を継続するフローを組んでください。これが「止まらないシステム」を作る秘訣です。
③ インメモリ処理とデータベースの境界線
数万行程度ならVB.NET内でリストに入れて処理しても良いですが、百万行を超えるなら、読み込んだ先からSQL ServerやSQLiteにバルクインサートする設計にしましょう。「データは流すもの」と意識を変えるだけで、コードの質が劇的に変わります。
—
先輩からのアドバイス
「マクロの記録」からステップアップしようとしている皆さん。VB.NETの`TextFieldParser`は、皆さんがこれまで培ってきた「Excel VBA」の思考を、より強力で安全な「エンタープライズ開発」へと橋渡ししてくれる強力なツールです。
「なぜ動くのか?」を意識して書いたコードは、必ず皆さんを助けてくれます。まずはこのコードをコピペして、手元の重たいCSVを読み込ませてみてください。処理が終わった瞬間の、「一瞬で終わる」感覚をぜひ味わってください。
ここをクリアすれば、もう皆さんは立派な業務自動化エンジニアの仲間入りです。応援していますよ!
