こんにちは!現場でバリバリ自動化を進めていると、こういう要望に直面したことはありませんか?
「毎月末、全国の部署から送られてくる大量のCSVファイルを、1つにまとめて集計してほしい……」
これを手作業でやろうとすると、エクセルを開いて、コピペして、2つ目以降のファイルはヘッダー(1行目のタイトル行)を消して……と、気が遠くなるような時間とミスが生まれますよね。
でも大丈夫。今回は、Windows環境なら追加のソフトも不要で、どこでも動くVBScript(Visual Basic Scripting Edition)を使って、この地獄のような作業を1秒で終わらせる「複数CSV自動結合ツール」の作り方を解説します。
ここをクリアすれば、FSO(ファイルシステムオブジェクト)を使ったファイル操作の基本はバッチリですよ。優しく丁寧に、プロの知見を交えて解説していきますね!
—
1. なぜVBScript×FSOなのか?
「今どきVBScript?」と思うかもしれませんが、侮るなかれ。
VBScriptは、Windowsに標準搭載されているスクリプト言語です。つまり、「メモ帳さえあれば書けて、インストール作業ゼロで、どのPCでも動く」という最強の機動力を持っています。
その中でも、ファイルやフォルダを自在に操るための最強の相棒がFSO(FileSystemObject)です。
エクセルマクロ(VBA)とほぼ同じ構文で動くため、業務自動化の第一歩としてこれほど適した技術はありません。
今回の処理のキモ:ヘッダーの制御
複数のCSVを結合する際の最大の罠は、「2つ目以降のファイルにあるヘッダー(1行目)が結合後も混ざってしまうこと」です。
[CSV 1] [CSV 2] [結合後]
ID,名前,売上 ID,名前,売上 ID,名前,売上
1,佐藤,100 + 1,鈴木,200 = 1,佐藤,100
2,高橋,150 2,田中,300 2,高橋,150
1,鈴木,200 ← ヘッダーが残っちゃう!
2,田中,300
これを防ぐために、FSOのテキストストリーム(TextStream)を使いこなし、「1ファイル目は全行書き込む、2ファイル目以降は2行目(データ行)から読み込む」という制御を実装します。
—
2. 完成版:複数CSV自動結合スクリプト
以下のコードをコピーして、メモ帳に貼り付けてください。
ファイル名を `csv_merge.vbs` とし、文字コード 「ANSI(またはShift-JIS)」 で保存すれば準備完了です。
‘ ==============================================================================
‘ スクリプト名: 複数CSV自動結合ツール
‘ 概要: 指定フォルダ内の全CSVを走査し、ヘッダーを維持したまま1つに統合する
‘ ==============================================================================
Option Explicit
‘ — 設定エリア —
‘ 処理対象のフォルダパス(末尾の「\」を忘れないように注意!)
Dim targetFolderPath
targetFolderPath = “C:\Work\CSV_Data\”
‘ 出力する統合ファイルのパス
Dim outputFilePath
outputFilePath = targetFolderPath & “Merged_Output.csv”
‘ ——————
Dim fso, folder, file, targetFile
Dim outStream, inStream
Dim isFirstFile
Dim lineCount, fileCount
‘ 1. FSOのインスタンス生成
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ フォルダの存在チェック
If Not fso.FolderExists(targetFolderPath) Then
MsgBox “指定されたフォルダが存在しません:” & vbCrLf & targetFolderPath, vbCritical, “エラー”
WScript.Quit
End If
‘ 2. 出力用ファイルの準備(すでに存在する場合は上書き作成)
‘ 引数: 2 = ForWriting, True = Create (ファイルがなければ作成)
Set outStream = fso.OpenTextFile(outputFilePath, 2, True)
Set folder = fso.GetFolder(targetFolderPath)
isFirstFile = True
fileCount = 0
lineCount = 0
‘ 3. フォルダ内の全ファイルをループ
For Each file in folder.Files
‘ 拡張子が「.csv」のファイルのみを対象とする(大文字小文字を区別しない LCase)
If LCase(fso.GetExtensionName(file.Name)) = “csv” Then
‘ 統合ファイル自身を読み込み対象に巻き込まないためのガード
If file.Path <> outputFilePath Then
fileCount = fileCount + 1
‘ 読み込み専用でファイルを開く (1 = ForReading)
Set inStream = fso.OpenTextFile(file.Path, 1)
Dim isHeaderLine
isHeaderLine = True ‘ 1行目判定用フラグ
Do While Not inStream.AtEndOfStream
Dim currentLine
currentLine = inStream.ReadLine
If isFirstFile Then
‘ 【ケースA】1つ目のファイルは、ヘッダーも含めて全行書き込む
outStream.WriteLine currentLine
lineCount = lineCount + 1
Else
‘ 【ケースB】2つ目以降のファイル
If isHeaderLine Then
‘ 1行目(ヘッダー)の場合は何もしない(スキップ)
isHeaderLine = False
Else
‘ 2行目以降(データ行)のみ書き込む
outStream.WriteLine currentLine
lineCount = lineCount + 1
End If
End If
Loop
‘ ストリームを閉じる(メモリリーク・リソース解放の基本)
inStream.Close
‘ 1つ目のファイル処理が完了したのでフラグを倒す
isFirstFile = False
End If
End If
Next
‘ 4. 出力ストリームを閉じる
outStream.Close
‘ 後始末
Set outStream = Nothing
Set folder = Nothing
Set fso = Nothing
‘ 完了メッセージ
If fileCount > 0 Then
MsgBox “結合が完了しました!” & vbCrLf & _
“処理ファイル数: ” & fileCount & ” 件” & vbCrLf & _
“総出力行数: ” & lineCount & ” 行” & vbCrLf & _
“保存先: ” & outputFilePath, vbInformation, “処理成功”
Else
MsgBox “対象となるCSVファイルが見つかりませんでした。”, vbExclamation, “確認”
End If
—
3. コードの重要ポイントを徹底解説
初心者から一歩抜け出すために、このコードで使われている「エンジニアの知見」をいくつかピックアップして解説します。
① `Option Explicit` はプロの証
VBScriptでは、変数を宣言せずにいきなり使うことができてしまいます(これを「暗黙の宣言」と呼びます)。しかし、これはタイポ(打ち間違い)によるバグの温床になります。
先頭に `Option Explicit` を書くことで、「変数は必ず `Dim` で宣言しなさい」という厳格なルールを自分に課し、無駄なデバッグ時間をゼロにできます。
② ファイルを開いたら必ず閉じる(ライフサイクル管理)
`fso.OpenTextFile` で開いたファイル(TextStreamオブジェクト)は、OSのリソースを占有します。
処理が終わったら必ず `inStream.Close` を呼び出し、スクリプトの最後にはオブジェクト変数を `Set … = Nothing` で解放する。この「使ったら返す」というリソース管理の意識が、大規模なバッチ処理でも安定して動くコードの秘訣です。
③ 大文字・小文字の罠を防ぐ `LCase`
ファイル拡張子を判定する際、`file.Name` が `”data.CSV”` なのか `”data.csv”` なのかで処理が分岐してしまう事故を防ぐため、`LCase(fso.GetExtensionName(…))` ですべて小文字に統一して比較しています。こうした「実務でのエラーを防ぐ工夫」がコードの品質を高めます。
—
4. 陥りやすいエラーと対策
開発現場でよくあるトラブルと、その処方箋をまとめておきます。
- エラー: 「パスが見つかりません (Path not found)」
- 原因: スクリプト内の `targetFolderPath` のパスが存在しない、またはフォルダ名の末尾に `\`(バックスラッシュ)が抜けている。
- 対策: パスは必ず絶対パスで指定し、最後のスラッシュを確認しましょう。
- 文字化けが発生する
- 原因: 保存したVBScriptの文字コードがUTF-8(BOMなし)になっている、または読み込むCSVがShift-JISなのにエディタのエンコードが合っていない。
- 対策: VBScriptファイルを保存する際は、メモ帳の「名前を付けて保存」から文字コードを ANSI に指定してください。
—
5. おわりに
いかがでしたか? FSOを駆使したこのスクリプトを導入すれば、毎月何時間もかかっていたコピペ作業が、ファイルをフォルダに放り込んでダブルクリックするだけで一瞬で終わるようになります。
ここをクリアしたあなたなら、ファイルのリネーム自動化や、ログファイルの監視など、他の業務自動化への応用も余裕です。
ぜひ自分の業務に合わせてパスを書き換え、あなたの職場で「自動化のヒーロー」になってくださいね!
