【VBA】複数CSVを個別シートに読み込むマクロ【ファイル名で自動命名】

A子さん

各CSVファイルを 別々のシートに保管 したい
ファイルごとにシート名を付けたい(=探しやすい)
後から編集・確認・印刷などを個別に行いたい

目次

▼完成イメージ

  • 複数CSVを選択
  • 各CSVの中身が新しいシートに1枚ずつ展開される
  • シート名は元のCSVファイル名になる

▼コード全文(そのままコピペOK)

Sub ImportCSVToSeparateSheets()
    Dim csvFiles As Variant
    Dim i As Long
    Dim tempWB As Workbook
    Dim tempWS As Worksheet
    Dim newWS As Worksheet
    Dim fileName As String

    ' CSVファイルを複数選択
    csvFiles = Application.GetOpenFilename("CSVファイル (*.csv),*.csv", _
                                           Title:="CSVファイルを選択(複数可)", _
                                           MultiSelect:=True)

    If VarType(csvFiles) = vbBoolean Then
        MsgBox "キャンセルされました。", vbExclamation
        Exit Sub
    End If

    Application.ScreenUpdating = False

    For i = LBound(csvFiles) To UBound(csvFiles)
        Set tempWB = Workbooks.Open(Filename:=csvFiles(i), ReadOnly:=True)
        Set tempWS = tempWB.Sheets(1)

        ' ファイル名(拡張子抜き)を取得
        fileName = VBA.Replace(VBA.Mid(csvFiles(i), InStrRev(csvFiles(i), "\") + 1), ".csv", "")

        ' シートを追加し、名前をファイル名に
        Set newWS = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
        On Error Resume Next
        newWS.Name = Left(fileName, 31) ' Excelのシート名上限:31文字
        On Error GoTo 0

        ' データをコピー
        tempWS.UsedRange.Copy Destination:=newWS.Range("A1")

        tempWB.Close SaveChanges:=False
    Next i

    Application.ScreenUpdating = True

    MsgBox "すべてのCSVファイルを読み込みました!", vbInformation
End Sub

▼なぜこのマクロが活躍するのか

CSV形式のデータって、本当に厄介です。

営業部から日報が日ごとに分割されたCSVで飛んでくる。経理からは部署ごとにCSVが分かれている。システムから自動出力されたCSVは月別に何十個もある——。

「これらをすべて1つのExcelファイルに統合して、シート分けして整理してほしい」という要望は、実務で本当によくあります。

手作業で1つずつ開いてコピペして、シート名を付けて……という作業を何十回も繰り返すのは、時間の無駄です。その間に人間のミスも増えます。

このマクロが解決すること。

  • 複数のCSVを一度に選択できる
  • 自動で新しいシートを作成
  • ファイル名がそのままシート名になるから、あとから探すのが楽
  • 全部終わるまで画面の更新を止めるから、処理が高速
  • ファイル名が31文字を超える場合でも自動でカット

つまり、面倒な下準備をすべて機械がやってくれるのです。

▼ポイント解説

処理項目内容
GetOpenFilenameCSVを複数同時に選択可能
Workbooks.Open一時的にCSVをブックとして開く
Sheets.Add新しいシートを追加
UsedRange.Copyデータをすべてコピー
newWS.Nameシート名をCSVのファイル名に自動で設定(31文字以内)

GetOpenFilename の魔法

通常のファイルダイアログなら、ファイルを1個ずつしか選べません。でも MultiSelect:=True を指定すると、Ctrl+クリックやShift+クリックで複数ファイルを一気に選択できるようになります。

選ばれたファイルのパスは配列で返ってきます。その配列を LBound から UBound までループ処理するので、何個選ばれても対応できるわけです。

キャンセルされた場合は VarType(csvFiles) = vbBoolean がTrue になるので、そこで処理を終了します。

ファイル名を抽出する仕組み

ここが地味に重要な部分です。

csvFiles(i) には C:\Users\Desktop\sales_2024_01.csv みたいなフルパスが入ります。これをシート名として使うわけにはいきません。

そこで、この処理をします。

  • InStrRev(csvFiles(i), "\") で最後の「¥」の位置を検出
  • VBA.Mid でそこから先の文字列(ファイル名部分)を抽出
  • VBA.Replace で「.csv」を削除

この3段階で、「sales_2024_01」という純粋なファイル名だけが残ります。

さらに Left(fileName, 31) で31文字以内に切り詰めるのは、Excelのシート名上限が31文字だからです。長すぎるファイル名でも対応できるように、という親心です。

なぜ「On Error Resume Next」を使うのか

シート名を設定するときに On Error Resume Next で囲まれています。

これは、もし既に同じシート名が存在していたり、シート名として使えない文字が含まれていた場合のエラーハンドリングです。

エラーが出ても処理を続行するので、データが失われることはありません。On Error GoTo 0 でエラーハンドリングを終了して、次のファイル処理に進みます。

ScreenUpdating でパフォーマンス向上

Application.ScreenUpdating = False は、ループ中に画面の再描画を止める指令です。

100個のCSVを読み込むとき、毎回毎回画面を更新していたら、信じられないくらい遅くなります。でも画面を更新しなければ、その間のVBA処理だけに集中できるので、処理速度が数倍速くなります。

最後に Application.ScreenUpdating = True で更新を再開すれば、ユーザーは完成したシートをまとめて見ることができます。

ReadOnly フラグの意味

Workbooks.OpenReadOnly:=True は、CSVを「読み取り専用」で開く指定です。

なぜそんなことをするのか。

CSVファイルは元々のシステムやアプリケーションが常に更新している可能性があります。もしそこに書き込みをしようとしたら、ファイルがロックされてエラーになるかもしれません。

だから、読み取り専用で開いて、データをコピーして、すぐに閉じてしまう。この一連の流れでは、ファイルに悪影響を与えません。

そしてどうせコピーして別のシートに貼り付けるだけなので、元のCSVを編集する必要もないわけです。

▼実務での活用パターン

パターン1:部署別・月別・担当者別のCSV

営業部が東京・大阪・名古屋の3営業所から、それぞれ月別レポートをCSVで提出してくる。つまり3×12=36個のファイル。

これを手作業で1個ずつ開いてコピペしていたら、丸一日かかってしまいます。しかも、シート名も手動で付けなくてはならないから、「東京_202401」みたいに人によって命名ルールが違うかもしれません。

このマクロなら、36個全部を一度に選択して、ボタン1つで完了。各CSVのファイル名がそのままシート名になるから、一貫性も保たれます。

パターン2:毎日分割されて届く帳票

基幹システムから日報が毎日CSVで自動出力される。1年で365個のファイル。

それを月別の親ファイルに統合して、あとから「3月分だけを確認したい」「7月の特定の日付を探したい」という要望に対応したい場合があります。

このマクロで毎月の1〜31個のCSVを一括読み込みすれば、1つのExcelファイルに31個のシートが並ぶわけです。タブをクリックするだけで日付を切り替えられます。

パターン3:個別ファイルの印刷用フォーマット

複数の部署から受け取ったCSVそれぞれに対して、同じテンプレートで印刷したい。

このマクロで各CSVをシートに展開したあと、「ページレイアウト」タブで「シート単位で改ページ」を設定すれば、シートごとに分かれた印刷が可能になります。

営業部が10個の支店からCSVを提出→マクロで10シートに展開→一気に10部の印刷出力、という流れで、業務はものすごく効率化します。

▼よくあるカスタマイズ案

カスタマイズ方法例
ヘッダーを除外して読み込みたい.UsedRange.Offset(1, 0).Resize(...).Copy に変更
ファイル名+日付でシート名をつけたいnewWS.Name = Format(Now, "yyyymmdd") & "_" & Left(fileName, 20)
空シートがあるときに削除If WorksheetFunction.CountA(newWS.Cells) = 0 Then newWS.Delete

ヘッダー行を除外したい場合

複数のCSVを統合するときに、1行目の見出し行(ヘッダー)を除外したいことがあります。

「商品ID」「商品名」「数量」「金額」みたいなヘッダーが、CSVごとに何度も繰り返されるのが邪魔だから、最初の1回だけにしたい——という要望ですね。

そういう場合は、コードの中の

tempWS.UsedRange.Copy Destination:=newWS.Range("A1")

この部分を、以下のように変更します。

tempWS.UsedRange.Offset(1, 0).Copy Destination:=newWS.Range("A1")

Offset(1, 0) は「範囲を1行下にずらす」という意味です。つまり、1行目を飛ばしてコピーします。

ただし、最初のシートには見出しを残したいなら、こんなふうに条件分岐できます。

If i = LBound(csvFiles) Then
tempWS.UsedRange.Copy Destination:=newWS.Range("A1")
Else
tempWS.UsedRange.Offset(1, 0).Copy Destination:=newWS.Range("A1")
End If

ファイル名+日付でシート名をつけたい

複数月分のCSVを一度に読み込むときに「2024年1月版」みたいに日時情報を付けたい場合があります。

そういう場合は、シート名を設定する部分を以下のように変更します。

newWS.Name = Format(Now, "yyyymmdd") & "_" & Left(fileName, 20)

Format(Now, "yyyymmdd") で「20240115」みたいな形式の日付が挿入されます。そこにアンダースコアを挟んで、ファイル名の最初の20文字を追加すれば、「20240115_sales」みたいなシート名になります。

31文字上限の関係で、日付8文字+アンダースコア1文字+ファイル名22文字の合計31文字までですね。

空シートがあるときに自動削除

選択したCSVの中に、データが1行も入っていない空のファイルが混じっていることがあります。そういう場合、空のシートを自動削除したくなります。

ループ処理の最後に、こんな条件を追加します。

If WorksheetFunction.CountA(newWS.Cells) = 0 Then newWS.Delete

WorksheetFunction.CountA は「空でないセルの個数を数える関数」です。0なら、つまり何も入っていないなら、そのシートを削除します。

▼よくあるつまずきポイント

ここではよくあるつまづきポイントに関してふれていきます。

「複数選択がされていない」というエラー

ファイルダイアログで1個だけCSVを選んだ場合と、複数個を選んだ場合で、返ってくる値の型が違うことがあります。

1個だけ選ぶと、文字列(String)で返ってきます。複数個選ぶと、配列(Array)で返ってきます。

このコードは MultiSelect:=True を指定しているので、複数選択を想定しています。なのに1個だけ選んでしまうと、配列ではなく文字列で返ってくるので、ループ処理がうまく動きません。

解決するには、以下のように条件分岐を追加します。

If VarType(csvFiles) = vbString Then
csvFiles = Array(csvFiles)
End If

1個だけ選ばれた場合を配列に変換してしまえば、ループ処理で統一的に扱えます。

シート名が被ってエラーが出る

同じ名前のCSVを複数回読み込もうとしたり、既存のシート名とかぶったりすることがあります。

このコードには On Error Resume Next があるので、エラーが出ても続行します。ただし、自動で名前が変更されるわけではなくて、デフォルト名(Sheet1, Sheet2…)になってしまいます。

もっとスマートに対応するなら、シート名の後ろに番号を付けるなんて方法があります。

Dim sheetName As String
Dim counter As Integer
sheetName = Left(fileName, 31)
counter = 1
While ThisWorkbook.Sheets(sheetName).Name = sheetName
sheetName = Left(fileName, 27) & "_" & counter
counter = counter + 1
Wend
newWS.Name = sheetName

こうすると、重複するファイル名なら「sales_001」「sales_002」みたいに自動で番号が付きます。

文字コードの問題でデータが文字化けする

CSVは本来、単純なテキストファイルです。ファイルの作られ方によって、文字コード(SJIS・UTF-8・EUCなど)が異なります。

このコードは Workbooks.Open で素直にCSVを開いているだけなので、Excelが自動で文字コードを判定して処理します。ほとんどの場合、うまくいきます。

ただし、特殊な文字コードのCSVが混じっていると、データが文字化けすることがあります。

その場合は、CSVをあらかじめExcelで開いて、UTF-8で保存し直すか、文字コード変換ツールで統一するなど、事前準備が必要です。

UsedRange が正確でないときがある

UsedRange は「使用中の範囲」を示します。ただし、一度フォーマットが設定されたセルは、データが削除されても「使用中」と判定されてしまうことがあります。

つまり、実際にはデータがないのに、余分な行までコピーされてしまうかもしれません。

そういう場合は、以下のように、データが入っている最後の行と列を明示的に指定する方法があります。

Dim lastRow As Long
Dim lastCol As Long
lastRow = tempWS.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lastCol = tempWS.Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
tempWS.Range("A1").Resize(lastRow, lastCol).Copy Destination:=newWS.Range("A1")

こうすれば、実際にデータが入っている範囲だけをコピーします。

▼関連する話題

複数ブックのデータを集約したい場合

このマクロは「複数のCSVを1つのExcelファイルに、シート分けして格納する」という目的です。

でも、要件によっては「複数のCSVを、1つのシートに全部統合してしまいたい」というケースもあるかもしれません。売上データを営業所ごとに集計して、全体集計シートに積み上げるみたいな。

その場合は、コピー先を動的に変更すればいいです。

Dim pasteRow As Long
pasteRow = ThisWorkbook.Sheets(1).Cells(ThisWorkbook.Sheets(1).Rows.Count, 1).End(xlUp).Row + 1
tempWS.UsedRange.Copy Destination:=ThisWorkbook.Sheets(1).Range("A" & pasteRow)

こうすると、1つのシートに複数CSVを縦積みできます。

特定の列だけを取り込みたい場合

CSVには10列あるけど、必要なのは「商品名」「数量」「金額」の3列だけ——という場合もあります。

そういう場合は、コピーする対象を絞ります。

tempWS.Range("B:D").Copy Destination:=newWS.Range("A1")

B列からD列だけをコピー、みたいに指定すればいいです。

フィルター・ソート・装飾を加えたい場合

データを読み込んだあと、自動的にフィルターを設定したり、ヘッダー行を装飾したり、セル幅を自動調整したいことがあります。

それはループの最後に、以下みたいなコードを追加すればいいです。

newWS.Range("A1").AutoFilter でフィルター設定
newWS.Columns.AutoFit でセル幅を自動調整
newWS.Range("1:1").Interior.Color = RGB(200, 200, 200) でヘッダー行をグレーに塗る

こういった加工も、マクロなら自動化できます。

▼実装時のチェックリスト

  • CSVファイルが選択できるか確認した
  • 複数ファイルを同時選択できるか試した
  • 各CSVのデータが正しくコピーされているか確認した
  • シート名がファイル名と一致しているか見た
  • 処理速度は実用的か(時間がかかりすぎていないか)
  • キャンセルボタンを押したとき正しく終了するか試した
  • 空のCSVが混じっていても大丈夫か確認した
  • シート名が被ったときはどう対応するか決めた

▼まとめ

複数のCSVを一気に読み込み、それぞれが独立したシートに自動で展開されるマクロです。

ファイル名がそのままシート名になるから、あとから探すのが楽。データの分類・加工・印刷・保存がしやすくなり、業務効率が格段にアップします。

営業日報、請求書、売上報告書、経費精算……など、毎日飛んでくるCSVの処理に使えます。

手作業で1個ずつ開いていた時間を、全部マクロに任せてしまえば、そのぶん別の仕事に時間を使える。それが自動化の本質です。

「複数CSVの統合」って、ビジネスシーンでは超よくある要望なんですよ。
このマクロがあれば、後輩に「やっておいて」と言う必要もなくなります。

関連記事

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

かもろぐ屋へようこそ。

Microsoft製品が大好きな現役社内SEです。
本業では、業務改善・運用・トラブル対応・効率化など、いわゆる「社内の困った」を何でも屋のように対応しています。

このブログでは主に、

VBA
Power Apps
AI

について、実体験ベースで発信しています。

特に最近は、AIを使ったアプリ開発やブログ運営の自動化にハマっています。
「AIがあれば簡単に作れる」と思って始めた結果、普通に壊れたり、詰んだり、課金したりしながら泥臭く進めています。

キラキラした成功談というより、

「実際どうだったのか」
「どこで詰まったのか」
「初心者でも本当にできるのか」

を、できるだけリアルに残すタイプのブログです。

なお、絶賛婚活中です。

コメント

コメントする

CAPTCHA


目次