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文字を超える場合でも自動でカット
つまり、面倒な下準備をすべて機械がやってくれるのです。
▼ポイント解説
| 処理項目 | 内容 |
|---|---|
GetOpenFilename | CSVを複数同時に選択可能 |
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.Open の ReadOnly:=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 StringDim counter As IntegersheetName = Left(fileName, 31)counter = 1While ThisWorkbook.Sheets(sheetName).Name = sheetName sheetName = Left(fileName, 27) & "_" & counter counter = counter + 1WendnewWS.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 LongDim lastCol As LonglastRow = tempWS.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).RowlastCol = tempWS.Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).ColumntempWS.Range("A1").Resize(lastRow, lastCol).Copy Destination:=newWS.Range("A1")
こうすれば、実際にデータが入っている範囲だけをコピーします。
▼関連する話題
複数ブックのデータを集約したい場合
このマクロは「複数のCSVを1つのExcelファイルに、シート分けして格納する」という目的です。
でも、要件によっては「複数のCSVを、1つのシートに全部統合してしまいたい」というケースもあるかもしれません。売上データを営業所ごとに集計して、全体集計シートに積み上げるみたいな。
その場合は、コピー先を動的に変更すればいいです。
Dim pasteRow As LongpasteRow = ThisWorkbook.Sheets(1).Cells(ThisWorkbook.Sheets(1).Rows.Count, 1).End(xlUp).Row + 1tempWS.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の統合」って、ビジネスシーンでは超よくある要望なんですよ。
このマクロがあれば、後輩に「やっておいて」と言う必要もなくなります。
関連記事








コメント