AccessのVBAでdatファイル出力

# 概要

dat出力はcsv出力に比べてちょっと癖があるので、その点についてのまとめ。

dat出力の方法は大きく
『DoCmd.TransferText使用』
『ADODB.Stream使用』
の2種類ある。

# DoCmd.TransferText

## エクスポート定義作成

下記のようにするとエクスポートの画面に移動できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/2007b464-7f8a-2f55-d707-b65f4426131c.png)

ここのファイル名（ファイルパス）はエクスポート定義に影響しない。
（任意でOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/bfe38233-addc-1b09-e3ed-dd61e71cf391.png)

 ↓ 左下の『設定』で定義の設定画面が開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/b0d38708-2810-b8e6-e636-8022732d648e.png)

 ↓ 区切り文字などいろいろ設定してエクスポート定義を保存できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/4e426201-487a-c134-5c80-c53d996b086d.png)

上記の画面の通り、 **改行コードは設定できない** 。
DoCmd.TransferTextを使う場合、改行コードは『キャリッジリターン + ラインフィード』となる。

もし別の改行コードで出力する必要があるなら、ADODB.Streamを使おう。

 ↓ 出力サンプルを確認する意味でも、最後の完了まで進める。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/878ff3da-cbee-5b9a-123e-cfde3c3d3079.png)

## DoCmd.TransferTextを使って出力

```vb:サンプルコード
'ヘッダー行の有無については、エクスポート定義の設定ではなく、
'DoCmd.TransferTextの引数の値で決まる。
Const is_header_add_ As Boolean = True

'文字コードについてはDoCmd.TransferTextの引数よりもエクスポート定義の
'設定が優先される。
'ここではDoCmd.TransferTextで例外にならないよう、いったん0=SJISにしておく。
Const encode_ As Long = 0

'dat拡張子を出力しようとすると例外になるので、
'一旦txtで出力しておいて出力直後にファイル名変更。
'Accessと同じフォルダーに出力。
DoCmd.TransferText _
    acExportDelim, _
    "lycoreco_export", _
    "lycoreco", _
    CurrentProject.Path & "\test.txt", _
    is_header_add_, _
    , _
    encode_

Name CurrentProject.Path & "\test.txt" As CurrentProject.Path & "\test.dat"
```

datファイル出力しようとすると、下記のように例外になってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/72429e68-957c-3cf5-c867-37a3561f12f4.png)

>実行時エラー3027
>データベースまたはオブジェクトは読み取り専用なので、更新できません。

## DoCmd.TransferText方式のまとめ

* 改行コードの指定ができない。
* 一旦txtやcsvに出力した後、datにリネームが必要。

# ADODB.Stream

## 参照設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ea48434a-1ae0-bc69-bf91-894b04021431.png)

## ADODB.Streamを使って出力

```vb:サンプルコード（ヘッダー有、タブ区切り、囲み文字無し）
'ストリーム準備。
Dim stream_ As New ADODB.Stream
stream_.Charset = "Shift-JIS"
stream_.Open


'出力対象のテーブル開く。
Dim rst_ As New ADODB.Recordset
rst_.Open _
    "lycoreco", _
    CurrentProject.Connection, _
    adOpenForwardOnly, _
    adLockReadOnly


'ヘッダー部出力。
Dim i_ As Long
For i_ = 0 To rst_.Fields.Count - 1
    stream_.WriteText rst_.Fields(i_).Name
    stream_.WriteText vbTab 'タブ区切り
Next
stream_.WriteText vbLf '改行はラインフィード

'rst_.MoveNextしていないので、この時点ではRecordsetのカーソルは1行目から動いていない状態。


'データ部出力。
Do Until rst_.EOF
    
    stream_.WriteText rst_.Fields("namae").Value
    stream_.WriteText vbTab 'タブ区切り
    stream_.WriteText rst_.Fields("age").Value
    stream_.WriteText vbLf '改行はラインフィード
    
rst_.MoveNext: Loop
rst_.Close


'ファイル出力してストリーム閉じる。
'Accessと同じフォルダーに出力。
stream_.SaveToFile CurrentProject.Path & "\test.dat"
stream_.Close
```

## ADODB.Stream方式のまとめ

* コードが長くなってしまう。
囲み文字ありの場合はエスケープも自前でやらないといけない、など面倒。
* その分自由度は高い。

# 蛇足

レジストリ変更すれば、DoCmd.TransferTextでダイレクトにdatファイルを出力できるらしい。
でも下記の理由あるからやめた方がいいと思う。

* セキュリティの為に『レジストリに無い拡張子はダメー』って制御がかかっているとのこと。
つまり、レジストリ変更によってセキュリティが下がる恐れがある。
* レジストリに依存する = 実行環境に依存する = 移植性が下がる。

https://support.microsoft.com/ja-jp/topic/access-%E3%81%A7%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E3%81%A8-%E8%AA%AD%E3%81%BF%E5%8F%96%E3%82%8A%E5%B0%82%E7%94%A8%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%8C%E3%81%82%E3%82%8B-0c4042f2-9f1d-f762-d95c-41f19d21bcce

# 参考サイトさん

https://ray88.hatenablog.com/entry/2021/09/19/094953

# バージョン

Windows 10 Pro 22H2 OSビルド 19045.2546
Microsoft Access for Microsoft 365 MSO (バージョン 2212 ビルド 16.0.15928.20196) 32 ビット