見出し画像

複数のCSVを1つのcsvファイルに結合するVBA

はじめに

VBAなどでデータを取り込む際に、CSVファイルを扱う機会があると思います。
その際に、csvファイルが複数あるため何度もファイルを開く動作が煩わしくありませんか?

私の場合、社内システムでデータを抽出するときに
複数の条件ごとでデータを抽出、エクセルに取り込んで管理、分析するのですが
CSVファイルが10個以上になるので
取り込む際にCSVファイルを1つのファイルに結合していました。
その時の結合するVBAを紹介したいと思いますので
ぜひ活用してみて下さい!!

コードの内容

Option Explicit
Sub csvを結合()
    Const ForReading   As Long = 1
    Const TristateAnsi As Long = 0   ' ANSI(Shift-JIS)で読み込み
    Dim fso        As Object
    Dim fld        As Object
    Dim fil        As Object
    Dim ts         As Object
    Dim wbMaster   As Workbook
    Dim ws         As Worksheet
    Dim FolderPath As String
    Dim TimeStamp  As String
    Dim SaveName   As String
    Dim line       As String
    Dim arr        As Variant
    Dim rowIndex   As Long
    Dim lineCount  As Long
    Dim firstFile  As Boolean
    Dim j          As Long
    Dim MaxCols    As Long
    Dim stm        As Object
    Dim i          As Long
    Dim lineOut    As String
    Dim cellVal    As Variant
    '―――――――――――――――――――――――
    ' 1. フォルダ選択
    '―――――――――――――――――――――――
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "CSVファイルが入ったフォルダを選択してください"
        If .Show <> -1 Then Exit Sub
        FolderPath = .SelectedItems(1)
    End With
    '―――――――――――――――――――――――
    ' 2. パフォーマンス最適化
    '―――――――――――――――――――――――
    With Application
        .ScreenUpdating = False
        .EnableEvents = False
        .Calculation = xlCalculationManual
    End With
    '―――――――――――――――――――――――
    ' 3. マスター用ワークブック&シート準備
    '―――――――――――――――――――――――
    Set wbMaster = Workbooks.Add(xlWBATWorksheet)
    Set ws = wbMaster.Sheets(1)
    ws.Name = "MergedData"
    ' 全セルを文字列扱いに設定 → E表記・桁落ち防止
    ws.Cells.NumberFormat = "@"
    rowIndex = 1
    firstFile = True
    MaxCols = 0
    '―――――――――――――――――――――――
    ' 4. FSOでCSVをテキスト読み込み&マージ
    '―――――――――――――――――――――――
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set fld = fso.GetFolder(FolderPath)
    For Each fil In fld.Files
        If LCase(fso.GetExtensionName(fil.Name)) = "csv" Then
            Set ts = fil.OpenAsTextStream(ForReading, TristateAnsi)
            lineCount = 0
            Do While Not ts.AtEndOfStream
                line = ts.ReadLine
                lineCount = lineCount + 1
                arr = Split(line, ",")
                ' 最初のファイル1行目で列数を記憶
                If firstFile And lineCount = 1 Then
                    MaxCols = UBound(arr) + 1
                End If
                ' 最初のファイルはヘッダー+全行、
                ' 2つ目以降は2行目以降のみを取り込む
                If firstFile Or lineCount > 1 Then
                    For j = 0 To UBound(arr)
                        ws.Cells(rowIndex, j + 1).Value = arr(j)
                    Next j
                    ' 列数揃えのため空セルも埋める
                    If UBound(arr) + 1 < MaxCols Then
                        For j = UBound(arr) + 1 To MaxCols - 1
                            ws.Cells(rowIndex, j + 1).Value = ""
                        Next j
                    End If
                    rowIndex = rowIndex + 1
                End If
            Loop
            ts.Close
            firstFile = False
        End If
    Next
    '―――――――――――――――――――――――
    ' 5. 設定を元に戻す
    '―――――――――――――――――――――――
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
    End With
    '―――――――――――――――――――――――
    ' 6. 保存ファイル名作成
    '―――――――――――――――――――――――
    TimeStamp = Format(Now, "yyyymmdd_HHmmss")
    SaveName = "結合済みcsv_" & TimeStamp & ".csv"
    '―――――――――――――――――――――――
    ' 7. ADODB.StreamでUTF-8 BOM付きCSVを書き出し
    '―――――――――――――――――――――――
    On Error Resume Next
    Set stm = CreateObject("ADODB.Stream")
    On Error GoTo 0
    If Not stm Is Nothing Then
        With stm
            .Type = 2               ' adTypeText
            .Charset = "utf-8"
            .Open
            For i = 1 To rowIndex - 1
                lineOut = ""
                For j = 1 To MaxCols
                    cellVal = ws.Cells(i, j).Value
                    lineOut = lineOut & CStr(cellVal)
                    If j < MaxCols Then lineOut = lineOut & ","
                Next j
                .WriteText lineOut & vbCrLf
            Next i
            .Position = 0
            .SaveToFile FolderPath & "\" & SaveName, 2  ' adSaveCreateOverWrite
            .Close
        End With
    Else
        ' ADODB.Stream が使えない場合は Shift-JIS で保存
        ws.Parent.SaveAs FileName:=FolderPath & "\" & SaveName, _
                         FileFormat:=xlCSV, Local:=True
    End If
    '―――――――――――――――――――――――
    ' 8. マージ用ワークブックを閉じる
    '―――――――――――――――――――――――
    wbMaster.Close SaveChanges:=False
    '―――――――――――――――――――――――
    ' 9. 完了メッセージ
    '―――――――――――――――――――――――
    MsgBox "【完了】CSVを統合して保存しました:" & vbCrLf & _
           FolderPath & "\" & SaveName, vbInformation
End Sub

処理の内容

1. フォルダ選択
• ユーザーにCSVファイルが入っているフォルダを選ばせる。
2. パフォーマンス最適化
• 画面更新やイベント処理を一時停止し、高速処理に切り替える。
3. マスターブック準備
• 新しいExcelブックを作成し、データ統合用のシートを作る。
• セル形式を「文字列」にして、数値が勝手に変換されないようにする。
4. CSVファイルの読み込み&結合
• FSO(FileSystemObject)を使ってCSVファイルを1行ずつ読み込み。
• 最初のCSVだけヘッダーを取り込み、以降は2行目以降のみ結合。
• 列数が異なるCSVも対応。列数を合わせて整形。
5. Excel設定を元に戻す
• 最適化を解除し、通常のExcel動作に戻す。
6. 保存ファイル名の生成
• タイムスタンプ付きのファイル名を生成。
7. UTF-8(BOM付き)で保存
• ADODB.Streamを使ってCSVファイルとして出力。
• もしADODBが使えない場合は、Shift-JIS形式で保存。
8. Excelファイルを閉じる
• 作業用のマスターブックは保存せずに閉じる。
9. 完了メッセージ表示
• 保存場所とファイル名を表示して処理完了を知らせる。


補足ポイント

• Shift-JIS対応:入力ファイルの読み込み時はShift-JIS(ANSI)で開いている。
• 文字化け防止:出力はUTF-8(BOM付き)なので、Excelや他のツールで文字化けしにくい。
• 安全性と汎用性:ADODB.Streamが使えなくても代替手段があるので実用性高い。

いいなと思ったら応援しよう!