- xlsx 等を編集したあと csv で保存して別アプリで読み込むワークフローなのだけれど、Excel には「別名で保存」的なものがないので、csv で保存するたび csv ファイルの方が編集対象になってしまって作業ミスが頻発するので何とかしたい。
- そもそも csv 形式が2種類あったり、手動保存だとミスが起こりがちなので、シート上のボタンひとつで csv 保存できるようにしたい。
マクロで簡単にできそうなもんだけれど地味に面倒
単にいま作業中のシートを csv で保存するだけなら
'CSV UTF-8 で保存
'シフトJISがよければ FileFormat を xlCSV にする
ActiveWorkbook.SaveAs "csvファイル名", FileFormat:=xlCSVUTF8
で終わりなのだけど、これだと手動で csv 保存した場合同様、それ以後は csv ファイルの方が編集対象になってしまう。
これを避けるには、作業中のシートを複製して新しいブックを作って、それを csv で保存して、そのブックは捨てる、という、どんだけ無駄な事をするんだよ、とツッコみたくなるような手法になる。
'作業中のシートを複製して新規ブックを作成
'以後その新規ブックが ActiveWorkbook になる
activesheet.Copy
'CSV UTF-8 で保存
ActiveWorkbook.SaveAs "csvファイル名", FileFormat:=xlCSVUTF8
'csv出力用に作ったブックを変更確認はせずに閉じる
'ActiveWorkbook は元のブックに戻る
ActiveWorkbook.Close SaveChanges:=False
コードも見た目は簡単なんだけどね。VBAをよく知らん頃にこのコードを初めて見たときは何やってんのかしばらく分からんかった。Copy
の1行だけでいろいろ起こりすぎ。
ちなみに Close
時の SaveChanges:=False については、記事を書くにあたって改めて検証したところ、基本なくとも問題ないのだけど、もしセーブに失敗した場合、セーブせず閉じていいか聞かれて混乱するので入れといた方が親切。
改めて SaveChanges
の挙動について調べてみたところ、省略時は True
とも False
とも違う挙動 なのね。そういう事はマニュアルにちゃんと書いてよ。
True
:変更があれば保存して閉じるFalse
:変更があっても保存せず閉じる- 省略時:変更があったらダイアログで問い合わせる
サンプルコード
シートを複製したあとにセーブに失敗してマクロが停止すると訳がわからない状態になるので、一応エラー処理も入れてみた。
'作業中のシートをブックと同名で csv 保存
'これをボタンに登録すれば1クリックで csv 保存できる
Sub SaveCsvThisSheet()
'ブックのファイル名の拡張子を csv に変更
Dim csvPath As String
csvPath = Left(ActiveWorkbook.Name, InStrRev(ActiveWorkbook.Name, ".")) & "csv"
'ブックのパスと結合
csvPath = ThisWorkbook.path & "\" & csvPath
'作業中のシートを csv 保存
SaveCsv activesheet, csvPath
End Sub
'シートを指定ファイル名で csv 保存
Sub SaveCsv(sheet As Worksheet, csvPath As String)
'シートを複製して新規ブック作成。以後それが AcriveWorkbook
sheet.Copy
'上書き確認をせず上書きするよう、ダイアログ抑止
Application.DisplayAlerts = False
'CSV UTF-8 で保存
On Error Goto SaveError
ActiveWorkbook.SaveAs csvPath, FileFormat:=xlCSVUTF8
On Error Goto 0
'ダイアログ抑止解除
Application.DisplayAlerts = True
'csv保存用に複製したブックを変更確認はせずに閉じる
ActiveWorkbook.Close SaveChanges:=False
Exit Sub
SaveError:
MsgBox csvPath & " を保存できませんでした"
Resume Next
End Sub
SaveAs
で確認なしでファイルを上書きする方法については、セーブ前にファイルを消す方法と、Application.DisplayAlerts = False で上書き確認ダイアログを抑止する方法 があるけど、今回はエラー処理を1つにまとめるため後者にした。