【実務中級者への登竜門】混在するCSVの文字コードを自動判別せよ!FSOを使いこなす極限のテクニック
「マクロの記録」から一歩踏み出し、自分でコードを書き始めた皆台、こんにちは。
現場の自動化を支えるエンジニアとして、皆さんが直面する「現実的な壁」を一緒に乗り越えていく準備はできていますか?
今日扱うテーマは、実務で必ずと言っていいほど遭遇する「文字コードの混在」という厄介な問題です。
「CSVを読み込むプログラムを書いたのに、特定のファイルだけ文字化けする……」
「Shift_JISだと思って処理したら、実はUTF-16だった……」
そんなトラブルに、もう振り回される必要はありません。FileSystemObject(FSO)の深淵にある「ある特性」を利用して、ファイルを自動判別し、その結果をレポートにまとめる。この技術をマスターすれば、あなたのスクリプトの信頼性は格段に跳ね上がります。
さあ、極限の知見の世界へ踏み出しましょう。
1. なぜ「文字コードの判定」が必要なのか?
業務システムから出力されるCSVは、必ずしもルール通りではありません。
- 古い基幹システムから出るもの $\rightarrow$ Shift_JIS (ANSI)
- Webシステムや最新のツールから出るもの $\rightarrow$ UTF-16 (Unicode)
これらが一つのフォルダに混在しているとき、プログラム側で「このファイルはどちらの形式か?」を判断せずに読み込むと、文字化けが発生したり、最悪の場合、プログラムが異常終了したりします。
自動化エンジニアの使命は、「イレギュラーな状況下でも、止まらずに正しく動く仕組み」を作ることです。
2. FSOの隠れた武器:`OpenTextFile` の `Format` 引数
ここで登場するのが、`FileSystemObject` の `OpenTextFile` メソッドです。
このメソッドには、ファイルをどのような形式で開くかを指定する `Format` という引数があります。
| 定数名 | 値 | 説明 |
|---|---|---|
| `TristateUseDefault` | `0` | システムの既定(通常は Shift_JIS / ANSI) |
| `TristateTrue` | `-1` | Unicode (UTF-16) |
| `TristateFalse` | `-2` | ASCII |
ここが設計の肝です。
VBScriptには「文字コードを自動判定する」という便利な関数は存在しません。しかし、「あえてUnicodeとして開いてみて、中身が正しく読めるか試す」という「プロトタイプ・テスト」の手法をとることで、判定が可能になります。
判定のロジック(アーキテクトの思考)
1. ファイルを「Unicodeモード」で開いてみる。
2. 読み込んだ文字列の中に、「Null文字(Chr(0))」が含まれていないかチェックする。
3. もしNull文字が混じっていたら、それは「Shift_JISのデータを無理やりUnicodeとして解釈した結果」である可能性が極めて高い。
4. Null文字がなければ、それは正真正銘のUnicodeである。
3. 実装:文字コード判定&レポート作成スクリプト
それでは、実際に動作するコードを見ていきましょう。このコードは、指定したフォルダ内のCSVをスキャンし、判別結果を `report.csv` に出力します。
' ==========================================================================
' テーマ: CSV文字コード自動判別・分類レポート作成スクリプト
' 作成者: 伝説のチーフアーキテクト
' 概要: FSOを用いてCSVの文字コード(SJIS/UTF-16)を判定し、一覧を出力する
' ==========================================================================
Option Explicit
Dim fso, targetFolder, reportFile, fileItem
Dim targetPath, reportPath
' --- 設定エリア ---
targetPath = "C:\Work\TestCSV" ' 調査したいフォルダのパス
reportPath = "C:\Work\encoding_report.csv" ' レポートの出力先
' ------------------
Set fso = CreateObject("Scripting.FileSystemObject")
' 1. フォルダの存在確認
If Not fso.FolderExists(targetPath) Then
MsgBox "エラー: 指定されたフォルダが見つかりません。" & vbCrLf & targetPath, vbCritical
WScript.Quit
End If
' 2. レポートファイルの作成(ヘッダー書き込み)
Set reportFile = fso.CreateTextFile(reportPath, True)
reportFile.WriteLine "FileName,DetectedEncoding,FilePath"
' 3. フォルダ内のファイルを走査
Dim folder
Set folder = fso.GetFolder(targetPath)
For Each fileItem In folder.Files
' CSVファイルのみを対象とする
If LCase(fso.GetExtensionName(fileItem.Name)) = "csv" Then
Dim encoding
encoding = DetectEncoding(fileItem.Path)
' レポートに書き出し(カンマ区切り)
reportFile.WriteLine fileItem.Name & "," & encoding & "," & fileItem.Path
End If
Next
reportFile.Close
MsgBox "完了しました!" & vbCrLf & "レポート: " & reportPath, vbInformation
' ==========================================================================
' 関数: DetectEncoding
' 引数: filePath (String) - ファイルのフルパス
' 戻り値: String - "UTF-16" または "Shift_JIS"
' ==========================================================================
Function DetectEncoding(filePath)
Dim ts, sampleText, i
Dim isUnicode : isUnicode = True
On Error Resume Next ' ファイルが開けない場合のエラー対策
' 【極限の知見】Unicodeモード(TristateTrue = -1)で開いてみる
Set ts = fso.OpenTextFile(filePath, 1, False, -1)
If Err.Number <> 0 Then
DetectEncoding = "Error(FileOpenFailed)"
Exit Function
End If
' 最初の100文字程度を読み込んで検証
sampleText = ts.Read(100)
ts.Close
If Err.Number <> 0 Then
DetectEncoding = "Error(ReadFailed)"
Exit Function
End If
On Error GoTo 0
' 文字列の中に Null文字 (Chr(0)) が含まれているかチェック
' Shift_JISをUnicodeとして無理やり開くと、文字の間にNullが入り込む特性を利用
If InStr(sampleText, Chr(0)) > 0 Then
isUnicode = False
End If
If isUnicode Then
DetectEncoding = "UTF-16"
Else
DetectEncoding = "Shift_JIS"
End If
End Function
4. コードの徹底解説:ここが「プロ」の仕事
① `On Error Resume Next` の戦略的配置
実務では、ファイルが別のプログラムで開かれていて「使用中」であることが多々あります。エラーでスクリプトが止まるのは、自動化において「失敗」です。
ここでは、ファイルを開く・読むという「外部要因に左右される操作」の直前にだけエラー回避を入れ、エラーが発生した場合はエラー内容をレポートに書き出すように設計しています。
② `InStr(sampleText, Chr(0))` の魔法
これが今回最も重要なロジックです。
Shift_JIS(1バイト文字中心)を、無理やり2バイト単位のUnicodeとして解釈しようとすると、データの構造上、文字の間に「値が0のバイト」が混入します。これを `Chr(0)` として検出し、文字コードを逆算する。これは、低レイヤーの動作原理を理解している者にしか書けないテクニックです。
③ `LCase` による拡張子の判定
`fileItem.Name` が `.CSV`(大文字)でも `.csv`(小文字)でも正しく判定できるよう、`LCase` 関数で小文字に統一してから比較しています。こうした「些細な揺らぎ」を排除する姿勢が、堅牢なプログラムを生みます。
5. 陥りやすい落とし穴(トラブルシューティング)
このスクリプトを使う際に、以下の点に注意してください。
1. 空のファイル:
ファイルの中身が完全に空の場合、判定ロジックが機能しません。実務では「ファイルサイズが0より大きいか」のチェックを事前に入れるのがベストです。
2. 権限エラー:
管理者権限が必要なフォルダに対して実行すると、`OpenTextFile` で失敗します。実行ユーザーの権限を確認しましょう。
3. BOM(Byte Order Mark)の有無:
UTF-16にはBOMがあるものとないものがありますが、今回の `Chr(0)` 判定手法は、BOMの有無に左右されにくいため、非常に汎用性が高いのが強みです。
結びに:一歩先のエンジニアへ
いかがでしたか?
単に「ファイルを読み込む」だけでなく、「そのファイルがどういう性質を持っているか」を問い直す。この視点を持つことが、マクロ記録から脱却し、真の「自動化エンジニア」へと進化する鍵です。
今回のコードは、そのままあなたの業務に組み込めるレベルに仕上げてあります。まずはテスト環境で動かしてみてください。コードが意図通りに動き、レポートが生成された瞬間の感動は、あなたのエンジニア人生をより豊かなものにするはずです。
「ここをクリアすれば、VBScriptの基本はバッチリですよ。次なる課題へ進みましょう!」
