\ ポイント最大11倍! /

【Excel VBA】マクロで特定のセルの範囲を読み込みCSV出力する方法

  • 特定の範囲のセルを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によりループの最後の番号が取得できます。

つまり、配列の最小値と最大値を取得しているということですね。

これにより、配列のサイズに合わせて動的にループ回数が変更されます。

最小値が1で最大値が10だと、以下になります。
for i = 1 To 10
理解しづらいコードは、具体的な値に置き換えると理解が進みます。

3-4. セルの内容を型変換

cellValue = CStr(dataArray(i, j))

CStr()関数を使ってdataArray(i, j)を文字列型に変換しています。

なぜわざわざこのような処理をしているかという理由は以下の通り。

  • CSVでは全ての要素は文字列として扱うので変換したい
  • Null値は、空文字""に変換される

上記が原因とするエラーを回避できるようになります。

3-5. 「CSVファイルのお作法」に合わせる処理

CSVファイル作成には次のようなお作法があります。

  • 以下はダブルクオートで囲む
    • カンマ(,
    • 改行
  • ダブルクオートをエスケープ
    1. フィールド全体をダブルクォートで囲む
    2. フィールド内のダブルクォートを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に関する記事を公開しているので合わせてご覧ください!

» 参考:CFXLOG ExcelVBAの関連記事一覧を見てみる

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)