こんにちは、Ryoです。(2017/11/29更新・・・サンプルコード追加)
VBAで上書き保存処理をすると○○.tmpファイルに置き変わることがあったりして
困ることありませんか?私と同じ現象であれば、Local環境では問題なく社内LAN上での保存やNASのクラウド同期フォルダ上で処理する際に発生する現象で、非常に困っておりました。
今は根本的な対策になっていないかもしれませんが、本体ファイルの複製保存を利用して.tmp化を回避出来ていますので、その内容について書いていきます。
1.経緯と保存環境
先ず私の問題となっていたVBA処理としては、製品の特性検査行う際にPCに接続した
機器類を制御して規定条件下の特性データを読み、Excelへ書込みします。
その後、都度NASと同期しているクラウドフォルダに上書き保存することで、同時に
バックアップとしての処理も行える形にしていました。
以前はLocalへ測定都度保存し全製品の測定完了後に社内ネットワーク上のフォルダへ
保存する形だったのですが、一度PCが故障してHDDからデータを取り出すことも出来ず
その日の約1日分のデータが消失して再度測定し直すという失態を犯してから、上述の
バックアップを常時行う様に変えた次第です。
そして、その形に変えてから○○.tmpファイル化に悩まされることになります。
2.発生時の状況
PCのOSはWin10が1台、Win7が2台で全て同様の現象が発生していました。
計測時のサイクルタイムとしては15sec/ヶが1台、他2台は240sec/ヶとなっており、
上書き保存処理までの時間が長い方が、比較的発生しにくく(約5回に1回)、
サイクルタイムが短い場合は毎回.tmpファイル化するという状態です。
Excelは上書き保存する際に一時ファイルを作成して保存処理を行い、完了後に
リネームして元のファイル名とするようなので、保存処理までの時間によって変わる
ことからExcel側の処理がVBAの計測~保存処理に追いつかないのか?と思った訳です。
(ここまでに通信環境やセキュリティ設定なども試してましたが効果なし。。。)
3.対策
そして、悩み抜いた挙句にふと思ったのですが
「何も本体ファイルをネットワーク上に保存しなくても良いんじゃない?」
となり、本体ファイルをLocalとして計測完了時の都度保存はネットワーク上に「本体の複製」を作る形に変えたら、以後.tmpファイル化することはなくなりました。
この対処してから1ヶ月以上経過しますが、同様の現象は発生していないので大丈夫ではないかと思いますが、残る問題はネットワーク上で全て行う必要がある場合ですね。
◆ファイルの複製を作る(保存する)
Application.DisplayAlerts = False ActiveWorkbook.SaveCopyAs Filename:="D:\〇〇〇〇〇\" & "File名.xlsm" Application.DisplayAlerts = True
ファイル(ブック)の複製を保存するのは、これだけでOKです。
上書きの時はSaveAsでしたが、それをSaveCopyAsに変えるだけですね。
上下のApplication.DisplayAlertsは都度上書きしていくので、Excelのアラートを表示
させない為のものです。
4.【参考】.tmp化を防ぐサンプルコード
3.までは本体ファイルをローカル、複製をネットワーク上に保存する形で解決した旨を書いていますが、状況によっては全てネットワーク上で行う必要があるかもしれません。
以下に紹介するサンプルコードは、結構力技で対処案を考えてみたものですが、先ず本体ファイルをリネームしてネットワーク上に保存し、その後複製も作り保存します。
その複製は元のファイル名をそのまま使い、リネームしたファイルは後で削除するので「0000.xlsm」とします。
それらの処理が終了後、リネームしたファイル(0000.xlsm)を閉じて複製したファイルを再度開くので、ScreenUpdatingがきっちり動作してれば通常の「上書き保存」と何も変わらず済み、且つ.tmp化もしない状態になります。
(Excel2010は問題なし、2013以降はどう頑張っても画面のチラつきが出ます。。。)
後はネットワーク上に残ってしまうリネームファイル0000.xlsmの処理ですが、ここは本体ファイルのブックモジュールに「閉じる直前に発生するイベント」を使って、ファイルを閉じる際に削除させるので、終了時には消え去るようになります。
前置きが長くなってしまいましたが、以下がサンプルコードです。
◆標準モジュール側
Sub Save_Test1() 'ネットワークサーバ上に保存する際の.tmp化回避サンプルプログラム Dim F_Name, F_Path, Delete_Name As String '******前準備********** '画面固定化 Application.ScreenUpdating = False With ThisWorkbook 'アクティブブック名を取得 F_Name = .Name 'アクティブブックパスを取得 F_Path = .Path '最終的に削除する一時的なファイルとしてリネーム用 Delete_Name = .Path & "\0000.xlsm" End With '******ファイルリネームと複製作成、保存処理******** 'アラート表示無効化 Application.DisplayAlerts = False With ActiveWorkbook 'アクティブブック名をリネームし保存 .SaveAs Filename:=Delete_Name 'アクティブブックの複製を元の名前に戻し保存 '複製として保存することで.tmp化しない .SaveCopyAs Filename:=F_Path & "\" & F_Name End With 'アラート表示無効化解除 Application.DisplayAlerts = True '******複製とリネームファイルの入替処理******* '複製し保存したファイルを開く Workbooks.Open Filename:=F_Path & "\" & F_Name DoEvents '開いたファイルをアクティブにする Workbooks(F_Name).Activate DoEvents 'リネームしたファイルを閉じる Workbooks("0000.xlsm").Close DoEvents '画面固定化の解除 Application.ScreenUpdating = True 'ここまでの処理で元のファイルを複製として保存し、ファイル名も元に戻す 'サーバー内同一パスには"0000.xlsm"が残るので、ワークブックモジュールに '削除処理を記述する End Sub
この処理を実行すると指定フォルダ内に0000.xlsm(リネームしたファイル)が保存されますが、以降のブックモジュール側の処理で削除するので、大丈夫です。
◆ブックモジュール側(エディタのThisWorkbook)
Private Sub Workbook_BeforeClose(Cancel As Boolean) 'ブックを閉じる直前に実行するイベント処理 Dim Path_A, bk_Name As String With ThisWorkbook 'ネットワークサーバーに保存されている"0000.xlsm"のパスを指定 Path_A = .Path & "\0000.xlsm" 'アクティブブックの名前を取得 bk_Name = .Name End With '指定パスに"0000.xlsm"が有り、且つアクティブブック名が '"0000.xlsm"でなければ実行 If Dir(Path_A, vbDirectory) <> "" And bk_Name <> "0000.xlsm" Then Application.DisplayAlerts = False 'リネームした"0000.xlsm"を指定パスから削除 Kill Path_A Application.DisplayAlerts = True End If End Sub
ブックモジュール側はWorkbook_BeforeCloseを使うことで、閉じる直前に処理を実行してくれます。ここで何をしているかと言いますと、「標準モジュール側で本体→リネームして保存→複製(元の本体ファイル名として)保存→複製ファイル開く→リネームファイル閉じる」という処理をするので、このWorkbook_BeforeCloseイベントで処理を行う条件は「リネームファイルでは無い」ことを処理条件にしないと不用なエラーが出る為ですね。
後は条件を満たせば指定パスから該当のリネームしたファイルを削除する処理を実行します。
ファイルを閉じた後に確認すると、このように削除されてますね。
私の環境ではサンプルのような処理で.tmp化は防げているのですが、使用環境などによって原因も様々ですし、同様の結果にならないこともあるかもしれませんので、本例は一つの手段として参考程度に見てもらえればと思います。
5.まとめ
最初は.tmp化するのはWin7特有の現象かと思っていましたが、現在のWin10でも普通に発生していますから、なかなか根が深そうですね。。。
特に確証は無いのですが、これまでの実体験から感覚的に「上書き保存」処理さえしなければ、.tmp化しないようにも思えますので今回書きました処理で暫し様子を見ていこうと思っています。
以上がネットワーク上に保存する際の.tmpファイル化を防ぐ対処でした!
今回の記事が何かの参考になれば幸いです。
Ryo