- 特定の範囲のセルをCSV出力したい!
このような疑問にお答えします。
VBAでは、ちょっと工夫するとセルの特定範囲をCSV出力することができます。
コードの作り方はいくつもあると思いますが、本記事では処理スピードを上げるために配列を使った方法をご紹介します。
配列について馴染みのない方にとってはややとっつきにくいと思うので、本記事ではできるだけ丁寧な解説を心がけました。
特定のセルの範囲を読み込み、CSV出力する
以下が結論となるコードです。
Public Sub ExportRangeToCSV()
On Error GoTo ErrorHandler
Dim ws As Worksheet
Dim outputPath As String
Dim fileNum As Integer
Dim i As Long, j As Long
Dim dataArray As Variant
Dim outputLine As String
Dim cellValue As String
' 配列にデータを格納
Set ws = ThisWorkbook.Worksheets("Sheet1")
dataArray = ws.Range("A1:C10").Value ' 例: A1:C10 の範囲を出力
' 出力ファイルのパスを設定
outputPath = ThisWorkbook.Path & "\output.csv"
' ファイルを開く
fileNum = FreeFile
Open outputPath For Output As #fileNum
' データを CSV 形式で書き込む
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
outputLine = ""
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
cellValue = CStr(dataArray(i, j))
' カンマを含む場合、ダブルクォートで囲む
If InStr(cellValue, ",") > 0 Or InStr(cellValue, """") > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
' 値を出力行に追加
outputLine = outputLine & cellValue
' 最後の列以外はカンマを付ける
If j < UBound(dataArray, 2) Then
outputLine = outputLine & ","
End If
Next j
' 行を書き込む
Print #fileNum, outputLine
Next i
' ファイルを閉じる
Close #fileNum
MsgBox "CSV ファイルが正常に出力されました。", vbInformation
Exit Sub
ErrorHandler:
Dim err_message As String
Select Case Err.Number
Case 70
err_message = "ファイルへのアクセス権限がありません。ファイルが他のプログラムで開かれていないか確認してください。"
Case 75
err_message = "指定されたファイルパスが無効です。パスの長さや形式を確認してください。"
Case 76
err_message = "指定されたパスが見つかりません。保存先のフォルダが存在するか確認してください。"
Case 6
err_message = "ファイルサイズが大きすぎる可能性があります。データ量を減らすか、分割して保存してください。"
Case Else
err_message = "予期せぬエラーが発生しました。" & vbNewLine & _
"エラー番号: " & Err.Number & vbNewLine & _
"エラーの説明: " & Err.Description
End Select
MsgBox err_message, vbCritical, "エラー"
' ファイルが開いている場合は閉じる
On Error Resume Next
Close #fileNum
On Error GoTo 0
End Sub
処理の内容ごとに分割して、一つ一つ解説していきます。
1. 対象のセル情報を配列で取得
まずはCSVとして書き出したいデータが格納されているシートを指定します。
' 配列にデータを格納
Set ws = ThisWorkbook.Worksheets("Sheet1")
ちなみにThisWorkbook
は、マクロを実行しているブックを表します。
続いて先ほど指定したシートに対して、範囲を指定して変数に格納しましょう。
' A1:C10 の範囲を取得
dataArray = ws.Range("A1:C10").Value
たったこれだけで、dataArray
変数にデータが配列として格納されます。
セルの範囲を自動的に取得したい場合には、以下のコードでもOKです。
' 使用範囲を自動的に取得
dataArray = ws.UsedRange.Value
2. 出力CSVパスを設定
CSVを出力したいパスを指定します。
以下のように、変数にパス情報を格納しておくとコードが読みやすくなります。
' 出力ファイルのパスを設定
outputPath = ThisWorkbook.Path & "\output.csv"
ちなみにThisWorkbook.Path
は、いまマクロを書いている「このブックのパス」を表します。
そのため、output.csv
というファイルがブックと同じディレクトリに出力されます。
ここで、ダイアログを表示してCSVファイルを選択してもらうこともできます。
' 出力ファイルのパスを取得
outputPath = Application.GetSaveAsFilename( _
InitialFileName:=ThisWorkbook.Path & "\output.csv", _
FileFilter:="CSVファイル (*.csv), *.csv")
If outputPath = "False" Then Exit Sub ' ユーザーがキャンセルした場合
こちらの方が親切かもしれませんね。
3. CSVファイル形式で出力
今回のメインとなるコード、CSV出力の部分です。
' ファイルを開く
fileNum = FreeFile
Open outputPath For Output As #fileNum
' データを CSV 形式で書き込む
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
outputLine = ""
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
cellValue = CStr(dataArray(i, j))
' カンマを含む場合、ダブルクォートで囲む
If InStr(cellValue, ",") > 0 Or InStr(cellValue, """") > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
' 値を出力行に追加
outputLine = outputLine & cellValue
' 最後の列以外はカンマを付ける
If j < UBound(dataArray, 2) Then
outputLine = outputLine & ","
End If
Next j
' 行を書き込む
Print #fileNum, outputLine
Next i
' ファイルを閉じる
Close #fileNum
ちょっと長いので、要素分解してみましょう。
- ファイルを開く
- データをCSV形式で書き込む
- ファイルを閉じる
順番に解説します。
3-1. ファイルを開く
VBAではファイルを入出力する時に、重複のない「ID」のようなものを割り振って管理しています。
未使用の番号を取得するため、FreeFile
使います。
' ユニークなファイル番号を取得
fileNum = FreeFile
上記では、未使用の番号がfileNum
として取得できます。
続いて、このfileNum
を指定して新しいファイルを生成します。
' 書き込み用としてファイルを開く
Open outputPath For Output As #fileNum
Open [パス] For Output
とすることで、書き込み用としてファイルを開くことができます。(この場合は存在しないファイルを指定しているので、新規作成される)
これでCSV出力のための準備が整いました。
3-2. データをCSV形式で書き込む
続いて、先ほど取得した配列をループしてCSV形式で書き出します。
' データを CSV 形式で書き込む
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
outputLine = ""
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
cellValue = CStr(dataArray(i, j))
' カンマまたはダブルクォートを含む場合、ダブルクォートで囲んで処理
If InStr(cellValue, ",") > 0 Or InStr(cellValue, """") > 0 Then
cellValue = """" & Replace(cellValue, """", """""") & """"
End If
' 値を出力行に追加
outputLine = outputLine & cellValue
' 最後の列以外はカンマを付ける
If j < UBound(dataArray, 2) Then
outputLine = outputLine & ","
End If
Next j
' 行を書き込む
' Print の末尾にはシステムのデフォルト改行文字が追加される
Print #fileNum, outputLine
Next i
' ファイルを閉じる
Close #fileNum
コードが長めなので、順を追って解説します。
3-3. ループ処理
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
LBound
は配列のインデックス番号の「最小値」を取得し、UBound
は配列のインデックス番号の「最大値」を取得する関数です。
特別な設定をしなければLBound
の結果は1
となり、UBound
によりループの最後の番号が取得できます。
つまり、配列の最小値と最大値を取得しているということですね。
これにより、配列のサイズに合わせて動的にループ回数が変更されます。
3-4. セルの内容を型変換
cellValue = CStr(dataArray(i, j))
CStr()
関数を使ってdataArray(i, j)
を文字列型に変換しています。
なぜわざわざこのような処理をしているかという理由は以下の通り。
- CSVでは全ての要素は文字列として扱うので変換したい
Null
値は、空文字""
に変換される
上記が原因とするエラーを回避できるようになります。
3-5. 「CSVファイルのお作法」に合わせる処理
CSVファイル作成には次のようなお作法があります。
- 以下はダブルクオートで囲む
- カンマ(
,
) - 改行
- カンマ(
- ダブルクオートをエスケープ
- フィールド全体をダブルクォートで囲む
- フィールド内のダブルクォートを2つ連続させる(
""
)
これを実現するため、If InStr(cellValue, ",") > 0
以降のコードを追加しました。
この処理をしないと「列の境界線が正しく判断されない」など、書き出したCSVファイルが正常に読み出せないことがあります。
3-6. CSVファイルに書き出す
最後にPrint
ステートメントでファイルに書き出します。
' 行を書き込む
' Print の末尾にはシステムのデフォルト改行文字が追加される
Print #fileNum, outputLine
コメントにあるように、Print
ステートメントの末尾には改行コードが自動的に挿入されます。
3-7. ファイルを閉じる
最後に、開いたファイルを閉じます。
' ファイルを閉じる
Close #fileNum
ここで閉じないと、他のプロセスからファイルを開くことができなくなることがあります。
また、ファイルを閉じることでリソースを解放するという意味合いもあります。
4. エラーハンドリング
ErrorHandler
には、エラーの補足ロジックを書きます。
Public Sub ExportRangeToCSV()
On Error GoTo ErrorHandler
' メインとなるコードが入る...
ErrorHandler:
Dim err_message As String
Select Case Err.Number
Case 70
err_message = "ファイルへのアクセス権限がありません。ファイルが他のプログラムで開かれていないか確認してください。"
Case 75
err_message = "指定されたファイルパスが無効です。パスの長さや形式を確認してください。"
Case 76
err_message = "指定されたパスが見つかりません。保存先のフォルダが存在するか確認してください。"
Case 6
err_message = "ファイルサイズが大きすぎる可能性があります。データ量を減らすか、分割して保存してください。"
Case Else
err_message = "予期せぬエラーが発生しました。" & vbNewLine & _
"エラー番号: " & Err.Number & vbNewLine & _
"エラーの説明: " & Err.Description
End Select
MsgBox err_message, vbCritical, "エラー"
' ファイルが開いている場合は閉じる
On Error Resume Next
Close #fileNum
On Error GoTo 0
End Sub
まとめ
CSV出力のポイントは以下の通りです。
FreeFile
で重複のないファイル番号を取得Open ... For Output
でファイルを作成Print
ステートメントを使って書き出す
細かい事項はありますが、上記が理解できればCSV出力の実装は一通りできるはずです。
疑問点などありましたらコメント欄より質問をお願いします。
本ブログでは、他にもVBAに関する記事を公開しているので合わせてご覧ください!
コメント