VBAと日々のこぼれ話

  1. VBA

【VBA】Excelファイルが既に開かれているかの確認

ファイル操作前のチェック処理

ファイルのバックアップを行う際に、是非とも入れてほしいチェック

ファイルがオープンしているかは、私がバックアップ処理のコードを書く際に最初に思いつくチェック処理かも。

存在チェックも勿論大事ですが、

「適切なファイルのバクアップを取得すること」

これが、バックアップ処理で一番必要なことだと思うんですよね。
対象のファイルが開いている状態は、更新中?→コピー不可だし、そもそも最新バックアップファイルでない可能性があります。

ここではバックアップに対するチェック処理と取り上げましたが、他にもそのファイルに書き込みをしたい場合に他の人が使っていないかのチェックにも使えますね。

【スポンサーリンク】



OPENステートメントを利用する

ファイルの種類や共有ファイルかどうか等で色々とコードは変わってきますが、今回は、Excelファイルのサイズが大きくなっても処理速度があまり変わらないサンプルコードです。

サンプルコードは処理の結果としてメッセージ表示させていますが、ファンクション化して引数を対象ファイルのフルパス・戻り値をBoolean値等にして使ってあげると使い勝手が良いです。

ファイルサイズに問わず処理速度が変わらない理由

OPENステートメントでファイルをオープンする場合にどうしてExcelファイルのサイズが大きくなっても処理速度があまり変わらないのかというと、Excelファイルをブックとして開くわけではなくテキストとして開くためです。

通常Excelファイルを開く場合は、WorkbooksコレクションのOpenメソッド(Workbooks.Open)を利用します。

このOpenメソッドは、Excelファイルをブックとして開くためファイルサイズと処理速度は凡そ反比例します。イメージとしては、手動でExcelファイルを開く際にマウスでダブルクリックをしてExcelファイルを開くことが多いと思うのですが、ファイルサイズが大きなものは開くのに余計な時間がかかることがありませんか?それと同じような理由です。

今回はあくまでもファイルオープンに関するチェック処理でありファイル内のデータをどうこうする訳ではないので、より早く処理が可能なOPENステートメントでのチェック処理を行っています。

サンプルコード解説

前提

コード順に解説していこうと思ったのですが、一部順序を入れ替えています。

大前提となりますが、このチェック処理はErrオブジェクトのプロパティ(Err.Number)の値でチェックを実施したり、正しくチェックが出来るよう「Err.Clear」「On Error Resume Next」を利用したりとErrオブジェクトをフル活用しています。

次に注目してほしいのは、この判定はファイルがオープンされているかを確認している訳ではなく、ファイルが指定条件で開けたか否かの確認になっていることです。これは、自分(サンプルコード側)が指定した条件で開けない=他者がファイルを開いている(ファイルは既に開かれている)とみなすからです。

最後は、指定条件で開けたか否かは、Openステートメントでファイルを開き、すぐにクローズしていることです。これらOpen・Closeステートメントで発生したErr.Numberを取得してファイルが開けたかどうかを確認しています。
この説明で気が付いたかもしれませんが、それは「Err.Numberプロパティの中身」で説明するのでもう少しお待ちください。

肝となるErrオブジェクト

Errオブジェクトは、実行時エラー(マクロを実行している際に発生したエラー(理由は様々))に関する情報を保有するオブジェクトです。

エラーが発生するとオブジェクトのNumberプロパティの値に0以外の整数値が設定されます。(実行時エラーが発生しなければ0のまま)

ん、オブジェクト?
サンプルコードのどこにもErrオブジェクトを作成してないよ?
オブジェクトなら、変数宣言やSetステートメントでの格納(参照)が必要なのでは?

等と疑問に思うのではないでしょうか?一般的なオブジェクトは、まさにその通りです。

しかし、Errオブジェクトはコード内でインスタンス(Errオブジェクトの格納用変数)を作成する必要がありません
作成不要な理由は、グローバルな組込オブジェクトだからなのですが、かみ砕くと何の定義をしなくても使えます!ということです。

更に保持する実行時エラーに関する情報は、最新で発生した実行時エラーの情報を持っている(上書きされていく)ということです。

また今回は利用しておらずややこしくなるので省略しますが、エラー情報を任意に設定することも可能です。

実行時エラーを無視する「On Error Resume Next」

通常、マクロはエラーが発生すると警告を表示してストップします。

ですが、サンプルコードはExcelに対してOPENステートメントを実行し、それにエラーが発生するかどうかで対象Excelを確認しようとしているため、その判定前に実行時エラー発生で処理がストップされると困ります。

そこで「以降、エラーが発生しても無視して処理を続ける」という意味のこのステートメントを先頭に記載しています。

ただしこの「On Error Resume Next」は使い方に気を付けるべきステートメントです。

というのも、このステートメントが記述された以降、同プロシージャ内は全て実行時エラーが無視されるので、本来、検知すべき実行時エラーまで無視してしまう可能性があるからです。

Err.Clearメソッドで範囲を狭める

Err.Clearメソッドは、Errオブジェクトを初期化します。

範囲を狭めるというのは、ファイルを開く直前に初期化することでErr.Numberでの判定時に判定するErr.Clear以降からErr.Number判定間に発生した実行時エラーだと特定できるようにしている点です。

このサンプルでいえば、つまりOpen~Closeまでに発生したエラー(実行時エラーがあれば)だということになります。

Err.Numberプロパティの中身

Err.Numberプロパティには、最新の実行時エラーのエラー番号が格納されます。ここでサンプルコードを見てもらいたいのですが、サンプルコードでは、Err.Number判定までに該当のファイルを追記モードで「開いて、閉じる」という2つの処理が行われています。

そう。OpenとCloseという2つのステートメントが実行されているということは、実は(実行時エラーがあれば)Errオブジェクトに保存されるエラーはどちらのものが入っているか分からないということです。

何故なら先述した通り、Errオブジェクトは最新のエラー内容を1つしか保持しないためです。

ですが、Closeステートメントはファイルが1つも開いていない(Openしているものがない)状態で実行してもエラーは発生しません。よって、Open時のエラーが発生していても上書きされる確率はごくごくわずかです。更に、そもそもClose時の実行エラーは発生頻度が低いことも理由の一つです。

ですので、Open時のエラーとみなす(みなすことができる)訳です。

またダメ押しとばかりに通常はファイルの存在チェック等を通った後にオープン確認チェックを行うので、このチェック時の異常は「ファイルが既に開いている」とみなすことが多いです。

ごくまれに「Err.Number = 55(ファイルが既に開かれている)」をピンポイントでチェックに使用しているものを見かけますが、広くエラーを検知できる「Err.Number > 0」をお勧めします。どんなエラーでも発生すれば、正常な処理は行えませんからね。

【スポンサーリンク】



VBAの最近記事

  1. 【VBA】(VBAを始めたばかりの人が陥りがちな落とし穴) Excelシートの最終行を取得…

  2. 【VBA】QRコードを作成したい

  3. 【VBA】CSVを1行ずつ処理したい

  4. Excelシートの最終行を取得したい その1

  5. 【VBA】未だに苦手としていること

関連記事

【スポンサーリンク】




PAGE TOP