マクロでCSVを出力しようとして作業中のブックに SaveAs を実行すると、開いているブックそのものがCSVファイルに切り替わります。ほかのシートや数式は画面に残っていても、以後の保存先はCSVになり、元のブックを保存し忘れる原因になります。
おすすめは、作業中のブックはそのままにして、出力したいシートや範囲だけを新しいブックへ写してから保存し、その一時ブックを閉じる方法です。この記事では、シート単位と範囲指定の2つのパターンのコードを示し、ファイル名・保存先・上書きの扱いも説明します。
なぜ一時ブックを経由するのか
| 方法 | CSVを作れるか | 作業中のブックへの影響 |
|---|---|---|
ThisWorkbook.SaveAs でCSV形式を指定する |
作れる | ブックがCSVに切り替わる。保存されるのは表示中の1シートだけ |
ThisWorkbook.SaveCopyAs を使う |
作れない(元と同じ形式のコピーになる) | 影響なし |
シートや範囲を新しいブックへ写して SaveAs する |
作れる | 影響なし |
SaveCopyAs では保存形式を変えられません。CSVを作るには、3つ目の方法を使います。
パターン1:シートを丸ごとCSVに出力する
シートの Copy メソッドを引数なしで実行すると、そのシートだけを含む新しいブックが作られ、そのブックがアクティブになります。これを一時ブックとして、CSV形式で保存します。
Option Explicit
Public Sub ExportSheetToCsv()
Dim srcWs As Worksheet
Dim tmpWb As Workbook
Dim outPath As String
Dim errMsg As String
Set srcWs = ThisWorkbook.Worksheets("出力用")
outPath = "C:\work\csv_out\売上_" & Format(Now, "yyyymmdd_hhnnss") & ".csv"
On Error GoTo Failed
srcWs.Copy ' シートだけを含む新しいブックができる
Set tmpWb = ActiveWorkbook
With tmpWb.Worksheets(1).UsedRange
.Value = .Value ' 数式を値に置き換え、元ブックへの参照を切る
End With
Application.DisplayAlerts = False
tmpWb.SaveAs Filename:=outPath, FileFormat:=xlCSV
Application.DisplayAlerts = True
tmpWb.Close SaveChanges:=False
MsgBox "CSVを出力しました。" & vbCrLf & outPath, vbInformation
Exit Sub
Failed:
errMsg = Err.Description
Application.DisplayAlerts = True
On Error Resume Next
If Not tmpWb Is Nothing Then tmpWb.Close SaveChanges:=False
On Error GoTo 0
MsgBox "CSVの出力に失敗しました。" & vbCrLf & errMsg, vbExclamation
End Sub
このコードのポイントは次のとおりです。
srcWs.Copyの直後に、ActiveWorkbookを変数に入れる。あとで別のブックがアクティブになっても、一時ブックを確実に閉じられる- コピーしたシートの数式が元のブックのほかのシートを参照していると、外部参照になる。
.Value = .Valueで値に置き換えておけば、CSVに書かれる内容が保存した時点の値で固定される - エラーが起きた場合も、
DisplayAlertsを元に戻し、一時ブックを閉じてから処理を終える - 処理が終わっても、
ThisWorkbookの名前や形式は変わらない
出力元のシートは、表示した状態で実行してください。非表示のシートをコピーすると、環境によってはエラーになったり、非表示のまま新しいブックに入ったりすることがあります。
xlCSV で保存すると、Windowsの既定の文字コード(日本語環境では通常Shift_JIS)で書き出されます。UTF-8で出力する必要がある場合は、FileFormat の指定を変えたうえで、取り込み先で正しく読めるかを確認してください。
パターン2:シートの一部の範囲だけをCSVに出力する
見出しと明細の部分だけを出したいときや、集計表の一角だけを出したいときは、新しいブックを作って範囲を貼り付けます。
Public Sub ExportRangeToCsv()
Dim srcWs As Worksheet
Dim srcRng As Range
Dim tmpWb As Workbook
Dim lastRow As Long
Dim outPath As String
Dim errMsg As String
Set srcWs = ThisWorkbook.Worksheets("集計")
lastRow = srcWs.Cells(srcWs.Rows.Count, "A").End(xlUp).Row
Set srcRng = srcWs.Range("A1:F" & lastRow) ' A〜F列の見出しから最終行まで
outPath = "C:\work\csv_out\集計_" & Format(Date, "yyyymmdd") & ".csv"
On Error GoTo Failed
Set tmpWb = Workbooks.Add(xlWBATWorksheet) ' シート1枚だけの新しいブック
srcRng.Copy
tmpWb.Worksheets(1).Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
Application.DisplayAlerts = False
tmpWb.SaveAs Filename:=outPath, FileFormat:=xlCSV
Application.DisplayAlerts = True
tmpWb.Close SaveChanges:=False
MsgBox "CSVを出力しました。" & vbCrLf & outPath, vbInformation
Exit Sub
Failed:
errMsg = Err.Description
Application.DisplayAlerts = True
Application.CutCopyMode = False
On Error Resume Next
If Not tmpWb Is Nothing Then tmpWb.Close SaveChanges:=False
On Error GoTo 0
MsgBox "CSVの出力に失敗しました。" & vbCrLf & errMsg, vbExclamation
End Sub
貼り付けには xlPasteValuesAndNumberFormats(値と数値の書式)を使っています。CSVには、セルに表示されている形で値が書き出されるためです。値だけを貼り付けると、00123 と表示していた数値のコードや、日付の表示形式が変わってしまうことがあります。
出力する範囲の指定方法
| 出したい範囲 | 指定の例 |
|---|---|
| 決まった範囲 | srcWs.Range("A1:F200") |
| A列の最終行まで | 上のコードのように lastRow を使う |
| 空白行・空白列で囲まれた表全体 | srcWs.Range("A1").CurrentRegion |
| テーブル(ListObject) | srcWs.ListObjects("売上表").Range(見出しを含む) |
End(xlUp) で最終行を取るときは、空欄が混じらない列を基準にします。途中までしか値がない列を基準にすると、出力が途中で切れてしまいます。
オートフィルターで絞り込んだ範囲を Copy すると、通常は表示されている行だけが貼り付けられます。絞り込みを解除し忘れて一部の行しか出力されなかった、ということがないように、出力前にフィルターの状態を確認してください。
ファイル名と保存先
日付・時刻入りのファイル名
| 書き方 | 結果の例 | 向いている使い方 |
|---|---|---|
Format(Date, "yyyymmdd") |
20261006 |
1日に1回だけ出力する |
Format(Now, "yyyymmdd_hhnnss") |
20261006_143005 |
1日に何度も出力する |
書式の中で「分」を nn と書くと、「月」を表す mm と取り違えずに済みます。また、ファイル名に / や : は使えません。Format(Date, "yyyy/mm/dd") のような書式は、ファイル名には使わないでください。
保存先のフォルダ
- 保存先のフォルダは事前に作っておく。存在しないフォルダを指定すると、
SaveAsがエラーになる - フォルダがあるかどうかは、
Dir(フォルダのパス, vbDirectory)で確かめられる - ブックと同じフォルダに出力したいときは
ThisWorkbook.Pathをよく使う。ただし、OneDriveやSharePointの同期フォルダにあるブックでは、ローカルのパスではなくhttps://で始まるURLが返ることがある。その場合は、出力先を固定のローカルフォルダにするなどして、実際の出力先を確認してから使う
フォルダの確認は、出力処理の先頭に次のように入れます。
Const OUT_DIR As String = "C:\work\csv_out"
If Dir(OUT_DIR, vbDirectory) = "" Then
MsgBox "出力先のフォルダがありません。" & vbCrLf & OUT_DIR, vbExclamation
Exit Sub
End If
上書き確認の扱い
Application.DisplayAlerts = False にしておくと、同じ名前のファイルがあっても確認のメッセージを出さずに上書きします。時刻入りのファイル名ならまず重なりません。しかし、売上.csv のような決まった名前で出力する場合は、意図しない上書きが起きます。
決まった名前で出力するなら、上書きしてよいかを先に確かめる処理を入れておくと安全です。
If Dir(outPath) <> "" Then
If MsgBox("同じ名前のファイルがあります。上書きしますか?" & vbCrLf & outPath, _
vbYesNo + vbQuestion) = vbNo Then Exit Sub
End If
この確認は、一時ブックを作る前(srcWs.Copy や Workbooks.Add より前)に置きます。後ろに置くと、キャンセルしたときに一時ブックが開いたまま残ってしまいます。
サンプルコードでは、エラーで処理が途中で抜けた場合にも、確認メッセージを抑えたままほかの処理が動かないよう、エラー時の処理でも DisplayAlerts を True に戻しています。
出力したCSVを確かめる
- 出力先にファイルができていて、ファイル名の日付・時刻が想定どおりになっている
- 作業中のブックの名前(タイトルバーの表示)が変わっていない
- メモ帳などのテキストエディタで開き、見出し行・列数・最終行が元のシートや範囲と合っている
- コードや日付の列が、取り込み先で求められる形で出力されている
- 一時ブック(「Book1」のような名前のブック)が開いたまま残っていない
CSVをダブルクリックしてExcelで開くと、Excelが値を読み直して表示します。そのため、先頭の0が消えるなど、ファイルの中身と画面の見え方が違うことがあります。中身の確認はテキストエディタで行ってください。
よく使う変更箇所のまとめ
| 変えたいこと | 変更する箇所 |
|---|---|
| 出力するシート | Worksheets("出力用") のシート名 |
| 出力する範囲 | srcRng の指定 |
| 出力先のフォルダ | outPath のフォルダ部分 |
| ファイル名に入れる日付の細かさ | Format の書式 |
| 文字コード | FileFormat の指定(変更後は取り込み先で読めるか確認する) |
