VBAでテストを回していた頃、結果を手作業でコピーして残すのが面倒で、必ずCSVに書き出してバックアップするようにしていた。
手作業だとうっかり上書きしてしまうこともある。だから「実行したら結果が自動でCSVになり、日付付きのフォルダに残る」という状態を作っておくと安心できる。
この記事では、シートのCSV出力から文字コードの注意点、フォルダ操作、それらを組み合わせたバックアップマクロまで、実務でそのまま使える形でまとめました。

シート全体をCSV出力する(基本)
まずは最もシンプルな方法として、アクティブシート全体をCSV出力するコードです。
Public Sub ExportSheetToCSV()
Dim ws As Worksheet
Dim outputPath As String
Dim fileNum As Integer
Dim i As Long, j As Long
Dim lastRow As Long, lastCol As Long
Dim outputLine As String
Dim cellValue As String
Set ws = ThisWorkbook.ActiveSheet
' 最終行・最終列を取得
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
' 出力先パスを設定(Excelファイルと同じフォルダ)
outputPath = ThisWorkbook.Path & "\output.csv"
fileNum = FreeFile
Open outputPath For Output As #fileNum
For i = 1 To lastRow
outputLine = ""
For j = 1 To lastCol
cellValue = CStr(ws.Cells(i, j).Value)
' カンマ・ダブルクォートを含む場合はダブルクォートで囲む
If InStr(cellValue, ",") > 0 Or InStr(cellValue, """") > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
outputLine = outputLine & cellValue
If j < lastCol Then outputLine = outputLine & ","
Next j
Print #fileNum, outputLine
Next i
Close #fileNum
MsgBox "CSV出力が完了しました。", vbInformation
End SubActiveSheetを対象にしているので、どのシートでも使いまわせるEnd(xlUp)/End(xlToLeft)でデータのある最終行・最終列を自動取得- カンマやダブルクォートを含むセルは自動でダブルクォートで囲む(CSV形式のルール)
ただし、この書き方はセルを1つずつ読み書きしているので、データが数千行を超えたあたりから明らかに遅くなる。
範囲指定でCSV出力する(配列で高速化)
大量データを扱うなら、セルを1つずつ読み書きするのではなく、範囲を配列にまとめて取得してから書き出すほうが圧倒的に速い。
以下は、UsedRange(シートの使用中セル範囲)を配列で取得し、CSV用のエスケープ処理を関数に分けて整理したコードです。
Option Explicit
'===============================
' メイン処理
'===============================
Public Sub ExportUsedRangeToCSV()
On Error GoTo ErrorHandler
Dim dataArray As Variant
Dim outputPath As String
Dim fileNum As Integer
Dim i As Long
'--- 対象データを取得 ---
dataArray = GetSheetData("Sheet1")
'--- 出力ファイルパス ---
outputPath = ThisWorkbook.Path & "\output.csv"
'--- ファイルを開く ---
fileNum = FreeFile
Open outputPath For Output As #fileNum
'--- CSV形式で書き込み ---
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
Print #fileNum, ArrayRowToCSVLine(dataArray, i)
Next i
'--- ファイルを閉じる ---
Close #fileNum
MsgBox "CSVファイルを出力しました。", vbInformation
Exit Sub
'--- エラー処理 ---
ErrorHandler:
MsgBox GetErrorMessage(Err.Number, Err.Description), vbCritical
On Error Resume Next
Close #fileNum
End Sub
'===============================
' シートから使用中範囲を配列取得
'===============================
Private Function GetSheetData(sheetName As String) As Variant
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(sheetName)
GetSheetData = ws.UsedRange.Value
End Function
'===============================
' 1セル分のCSV用エスケープ処理
'===============================
Private Function EscapeCSVValue(value As Variant) As String
Dim cellValue As String
cellValue = CStr(value)
' 囲むべき条件:カンマ、ダブルクォート、改行を含む場合
If InStr(cellValue, ",") > 0 _
Or InStr(cellValue, """") > 0 _
Or InStr(cellValue, vbCr) > 0 _
Or InStr(cellValue, vbLf) > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
EscapeCSVValue = cellValue
End Function
'===============================
' 配列の1行をCSV文字列に変換
'===============================
Private Function ArrayRowToCSVLine(dataArray As Variant, rowIndex As Long) As String
Dim j As Long, line As String
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
line = line & EscapeCSVValue(dataArray(rowIndex, j))
If j < UBound(dataArray, 2) Then line = line & ","
Next j
ArrayRowToCSVLine = line
End Function
'===============================
' エラーメッセージ生成
'===============================
Private Function GetErrorMessage(errNum As Long, errDesc As String) As String
Select Case errNum
Case 70: GetErrorMessage = "アクセス権限がありません。ファイルが開かれていないか確認してください。"
Case 75: GetErrorMessage = "ファイルパスが無効です。"
Case 76: GetErrorMessage = "指定されたパスが見つかりません。"
Case 6: GetErrorMessage = "ファイルサイズが大きすぎます。"
Case Else
GetErrorMessage = "予期せぬエラーが発生しました。" & vbCrLf & _
"番号: " & errNum & vbCrLf & _
"説明: " & errDesc
End Select
End Function関数を分けているのは、あとで「日付フォルダにバックアップする」マクロに組み込むときに、GetSheetDataやArrayRowToCSVLineをそのまま呼び出せるようにするためです。
文字コード(Shift-JIS / UTF-8)に気をつける
ここは実務でいちばん引っかかりやすいポイントです。VBAの標準的なファイル出力(Open ... For Output)は、Windowsのデフォルト文字コードであるShift-JISでCSVを作成します。
Excelで開くだけなら問題ありませんが、僕は以前、このCSVをそのままPython側の別システムに渡したところ、文字化けして読み込めなかったことがあります。他システムに連携する場合はUTF-8が求められることが多いので、出力先に応じて使い分ける必要があります。
Shift-JISで出力する(デフォルト)
Open outputPath For Output As #fileNumの標準コードがそのままShift-JIS出力になります。追加の設定は不要です。
UTF-8で出力する(ADODB.Streamを使う)
UTF-8で出力したい場合はADODB.Streamを使います。
Public Sub ExportToCSV_UTF8()
Dim ws As Worksheet
Dim stream As Object
Dim i As Long, j As Long
Dim lastRow As Long, lastCol As Long
Dim outputLine As String
Dim cellValue As String
Dim outputPath As String
Set ws = ThisWorkbook.ActiveSheet
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
outputPath = ThisWorkbook.Path & "\output_utf8.csv"
' ADODB.Streamを使ってUTF-8で書き込む
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' テキストモード
stream.Charset = "UTF-8"
stream.Open
For i = 1 To lastRow
outputLine = ""
For j = 1 To lastCol
cellValue = CStr(ws.Cells(i, j).Value)
If InStr(cellValue, ",") > 0 Or InStr(cellValue, """") > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
outputLine = outputLine & cellValue
If j < lastCol Then outputLine = outputLine & ","
Next j
stream.WriteText outputLine & vbCrLf
Next i
stream.SaveToFile outputPath, 2 ' 2 = 上書き保存
stream.Close
MsgBox "UTF-8でCSV出力しました。", vbInformation
End Substream.Charset = "UTF-8"で文字コードを指定- BOM(バイト順マーク)なしのUTF-8で出力される
- Excelで直接開くと文字化けする場合があるが、テキストエディタやPythonでは正常に読める
フォルダを作成・選択する
フォルダを作成する
Sub CreateFolder()
Dim folderPath As String
folderPath = "C:\Users\YourName\Desktop\TestFolder"
If Dir(folderPath, vbDirectory) = "" Then
MkDir folderPath
MsgBox "フォルダを作成しました!"
Else
MsgBox "すでにフォルダがあります!"
End If
End Subフォルダがなければ作成、あればメッセージを表示するだけのシンプルな作りです。
フォルダ選択ダイアログを出す
保存先を毎回固定パスにしたくない場合は、ユーザーにフォルダを選ばせるダイアログを出します。
Function SelectFolder() As String
Dim folderDialog As FileDialog
Set folderDialog = Application.FileDialog(msoFileDialogFolderPicker)
If folderDialog.Show = -1 Then
SelectFolder = folderDialog.SelectedItems(1)
Else
SelectFolder = ""
End If
End Functionキャンセルされた場合は空文字を返すようにしているので、呼び出し側で必ず判定してください。
Sub TestSelectFolder()
Dim path As String
path = SelectFolder()
If path = "" Then Exit Sub
MsgBox "選択されたフォルダは:" & path
End Subフォルダ内のファイル名を一括取得する
フォルダの中に何が入っているか一覧化したいときはDir関数をループで使います。
Sub GetFileNamesInFolder()
Dim folderPath As String
Dim fileName As String
Dim i As Long
folderPath = SelectFolder() & "\"
If folderPath = "\" Then Exit Sub
fileName = Dir(folderPath & "*.*")
i = 1
Do While fileName <> ""
Cells(i, 1).Value = fileName
fileName = Dir
i = i + 1
Loop
End Sub選択したフォルダ内のすべてのファイル名を、ExcelのA列にズラッと表示します。
実務での使い分けを体感する:テスト結果を日付フォルダにバックアップする
ここまでのCSV出力とフォルダ操作を組み合わせると、「テストを実行したら、結果が自動でCSVになり、日付付きのフォルダに残る」というマクロが作れます。
僕がテスト結果をエビデンスとして残すときによく使っている形です。
Option Explicit
'===============================
' テスト結果を日付フォルダにバックアップして開く
'===============================
Public Sub BackupResultsToDateFolder()
On Error GoTo ErrorHandler
Dim basePath As String
Dim newFolder As String
Dim dataArray As Variant
Dim outputPath As String
Dim fileNum As Integer
Dim i As Long
'--- バックアップ先の親フォルダを選択 ---
basePath = SelectFolder()
If basePath = "" Then Exit Sub
'--- 日付フォルダを作成 ---
newFolder = basePath & "\" & Format(Now, "yyyymmdd_hhnnss")
If Dir(newFolder, vbDirectory) = "" Then
MkDir newFolder
End If
'--- テスト結果(Sheet1のUsedRange)をCSVに書き出す ---
dataArray = GetSheetData("Sheet1")
outputPath = newFolder & "\result.csv"
fileNum = FreeFile
Open outputPath For Output As #fileNum
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
Print #fileNum, ArrayRowToCSVLine(dataArray, i)
Next i
Close #fileNum
'--- 保存したフォルダをそのまま開く ---
Shell "explorer.exe """ & newFolder & """", vbNormalFocus
Exit Sub
ErrorHandler:
MsgBox GetErrorMessage(Err.Number, Err.Description), vbCritical
On Error Resume Next
Close #fileNum
End SubGetSheetData・ArrayRowToCSVLine・GetErrorMessageは「範囲指定でCSV出力する」の章で紹介した関数をそのまま使っています。CSV出力・フォルダ作成・フォルダを開く、という3つの操作を1つのマクロにまとめただけで、バックアップ作業がボタン1つで終わるようになります。
よくあるエラーと対処
ファイル・フォルダ操作は、コードが正しくても環境側の要因でエラーになることがあります。よく出るエラー番号と原因をまとめました。
| エラー番号 | 原因 | 対処 |
|---|---|---|
| 70 | アクセス権限がない | ファイルが他のプログラムで開かれていないか確認する |
| 75 | ファイルパスが無効 | パスの長さ・使用できない文字を確認する |
| 76 | 指定したパスが見つからない | 保存先フォルダが存在するか確認する(先にMkDirする) |
| 6 | ファイルサイズが大きすぎる | データ量を減らすか、分割して保存する |
意外と見落としがちですが、Shell "explorer.exe"でパスを渡すときは、パスをダブルクォートで囲む(""" & path & """")のを忘れるとフォルダ名にスペースが含まれた瞬間に動かなくなります。
よくある質問
本文で触れきれなかった細かい疑問をQ&Aでまとめておきます。
UTF-8で出力したCSVをExcelで開くと文字化けするのはなぜですか?
ADODB.Streamで出力したUTF-8はBOM(バイト順マーク)なしのため、Excelが文字コードを正しく判定できず文字化けすることがあります。Excelで直接開いて確認したい場合はShift-JIS出力を、他システムへの連携が目的ならUTF-8のまま渡して問題ありません。
セルを1つずつ書き込む方法と配列を使う方法、どのくらい速度が変わりますか?
数百行程度なら体感差はほぼありません。数千行を超えるあたりから、セル単位のアクセスを繰り返す書き方は明らかに遅くなります。データ件数が読めない場合は、最初から配列で読み込む書き方にしておくのが安全です。
フォルダ選択ダイアログでキャンセルするとどうなりますか?
SelectFolder関数は空文字を返します。呼び出し側でIf basePath = "" Then Exit Subのように判定していないと、空のパスに対してファイル操作を試みてエラー76(パスが見つからない)になります。
まとめ
CSV出力は「シート全体か範囲か」「Shift-JISかUTF-8か」で書き方が変わり、フォルダ操作は作成・選択・一覧取得・オープンの4つを組み合わせれば大抵の場面はカバーできます。
1つずつ覚えるよりも、この記事の最後のバックアップマクロのように組み合わせてしまったほうが、結局は実務で使い続けやすいです。

コメント