【VBA】CSVに配列の中身を書き出す|ADODB.Stream
作成日:2022-12-30
更新日:2025-09-27

配列をCSVに
書き出したい
書き出したい

Excelに書き出すのとは違うの?

文字コードが必要になるよ
ADODB.Streamで書き出す

文字コードを制御したいときには ADODB.Stream を使う
Public Sub SaveUtf8WithBom(byval filePath As String, byval content As String)
' UTF-8で書き込む(まずはBOMなしで)
Dim stTxt As Object: Set stTxt = CreateObject("ADODB.Stream")
With stTxt
.Type = 2 ' テキストモード
.Charset = "utf-8"
.Open
.WriteText content
.Position = 0
End With
' バイナリファイルを作成
Dim stBin As Object: Set stBin = CreateObject("ADODB.Stream")
With stBin
.Type = 1
.Open
' バイナリファイルにBOMを追加する
Dim bom(2) As Byte
bom(0) = &HEF
bom(1) = &HBB
bom(2) = &HBF
.Write bom
' テキストファイルをバイナリファイルにコピーする
stTxt.CopyTo stBin
' バイナリファイルをファイルに保存する
.SaveToFile filePath, 2
.Close
End With
' テキストファイルを閉じる
stTxt.Close
End Sub

文字コードを制御する?

日本語の文字化けを防ぐこと
BOM付きのUTF-8を使う

BOMについてはこちら
VBAでBOM付きにする手順
- テキストストリームにUTF-8で本文を書き込む
- バイナリストリームを開き、先頭にBOM(
EF BB BF
)を書き込む - テキストストリームの内容をコピーして結合する
- ファイルに保存する

そもそもADODB.Streamって何?

「データの入れ物」のこと
ADODB.Streamを開く

フタ付きの入れ物だから、まず開く必要がある
Dim st As Object
Set st = CreateObject("ADODB.Stream")
st.Type = 2 ' テキストモード
st.Charset = "utf-8" ' 文字コード設定
st.Open ' ←ここで「ストリームを開く」
st.WriteText "Hello"

.Open
すると、ストリームに次のことができる
- 文字列を書き込む
- ファイルから読み込む
- 位置を移動する
使い方の例
'列:列記号で指定
private const COL_LASTROW_BASE = "A" ' 最終行の基準とする列記号
'ヘッダー行、データ行の開始行: 行番号で指定
private const ROW_HEADER = 1
private const ROW_DATA_START = 2
Public Sub ExportSheetToCSV()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("対象シート")
' 出力列を定義
dim fields() as string
ReDim fields(0 To 4)
fields(0) = "A"
fields(1) = "C"
fields(2) = "E"
fields(3) = "F"
fields(4) = "G"
' 最終行、最終列を取得
Dim lastRow As Long, lastCol As Long
With ws
lastRow = .Range(COL_LASTROW_BASE & .Rows.Count).End(xlUp).Row
lastCol = .Cells(ROW_HEADER, .Columns.Count).End(xlToLeft).Column
End With
' CSV行データを格納する配列
Dim csvLines() As String
Dim rowData() As String
Dim line As String
Dim i As Long
' ヘッダー行のデータを格納する配列
ReDim rowData(LBound(fields) To UBound(fields))
For i = LBound(fields) To UBound(fields)
rowData(i) = CSVEscape(ws.Cells(ROW_HEADER, fields(i)).Value)
Next
' CSV行データを格納する配列
ReDim csvLines(0 To lastRow - ROW_DATA_START + 1)
' 1行目にヘッダー行を出力
line = Join(rowData, ",")
csvLines(0) = line
' 行データの処理(各行を1つずつstringにする)
Dim r As Long
For r = ROW_DATA_START To lastRow
For i = LBound(fields) To UBound(fields)
rowData(i) = CSVEscape(ws.Cells(r, fields(i)).Value)
Next i
' CSV1行にまとめる
line = Join(rowData, ",")
' CSV配列に追加
csvLines(r -ROW_DATA_START + 1) = line
Next r
' CSV文字列
Dim csvContent As String
csvContent = Join(csvLines, vbCrLf)
Dim csvFilePath As String
csvFilePath = "ここに保存先パスを指定する"
' CSVファイルに保存
SaveUtf8WithBom csvFilePath, csvContent
End Sub
'=== ダブルクォートを必要な時だけ付ける ===
Private Function CsvEscape(byval s As String) As String
Dim needQuote As Boolean
needQuote = (InStr(s, ",") > 0) Or (InStr(s, """") > 0) Or (InStr(s, vbCr) > 0) Or (InStr(s, vbLf) > 0)
If needQuote Then
CsvEscape = """" & Replace(s, """", """""") & """"
Else
CsvEscape = s
End If
End Function

ダブルクォートを必要な時だけ付ける(CsvEscape)って?

特殊文字が入っているときに
逃げる(エスケープ)処理
ダブルクオートはなぜ必要か
こんなときにダブルクオートが必要
- カンマ ( , ) が入っているとき
- CSVはカンマ区切りだから、「
山田,太郎」
をそのまま書いたら「2列」と解釈されてしまう 「"山田,太郎"」
で「1セルの文字列」と認識される
- CSVはカンマ区切りだから、「
- 改行 (CR/LF) が入っているとき
- 途中に改行があると、「ここで行が終わった」と誤解されてしまう
- ダブルクォート ( ” ) 自体が含まれるとき
" → ""
にエスケープして全体をクオートで囲む
こんなときはダブルクオートが不要
- 普通の文字列(カンマ・改行・ダブルクォートが無い値)
- 「
123」
や 「山田太郎」
のような文字列はクオート無しで安全
- 「

誤解を防ぐための””

ちなみに、いちど配列にするのがおすすめ
配列にする理由

CSV本文の組み立ては2通りある
1. 文字列を line & vbCrLf で「どんどん結合」していく方式
Dim sb As String
For r = 1 To lastRow
sb = sb & line & vbCrLf
Next
特徴
- 実装がシンプル。
- 数百~数千行くらいなら、これで十分
- 数万~数十万行になると 処理が極端に遅くなる
文字列結合が遅い理由
sb = sb & line
のたびに
新しいバッファを確保→中身を丸ごとコピーが起きる
2. 配列にためて、最後に Join する方式
Dim arr() As String, idx As Long
ReDim arr(1 To lastRow)
For r = 1 To lastRow
arr(idx) = line
idx = idx + 1
Next
sb = Join(arr, vbCrLf)
特徴
- 高速・省メモリ。文字列コピーが最小限。
- 1万行以上では圧倒的に有利。
- パフォーマンス改善効果が大きい
小規模でも配列にしておくと無難
配列でもオーバースペックにはならないため、損はない
参考

同じ処理をPythonでも書いてみよう
2022-12-30
編集後記:
この記事の内容がベストではないかもしれません。
記事一覧
-
ユーザーフォームを半透明にする 【VBA】ユーザーフォームを半透明にしてシートの内容が見えるようにする|waiting-form -
[VBA]fsoSingleton pattern 【VBA】FSO(“Scripting.FileSystemObject”)|シングルトン化して使う -
[VBA]終了のメッセージボックス 【VBA】マクロ終了時のメッセージ|タイム付きmsgbox -
時間計算のDateAdd 【VBA】DateAddで時間の足し算・引き算 -
[VBA]Vertical Paste1D array 【VBA】一次元配列を縦方向にシートに貼り付け【範囲をリサイズする】 -
[VBA]Paste 2D Arrayresize once 【VBA】二次元配列をシートに貼り付け【範囲をリサイズする】