マクロで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 の指定(変更後は取り込み先で読めるか確認する)
おすすめの記事