先日、ファイル操作を行うプログラムを作成している際にヘルプのお世話になるタイミングがありました。備忘録としてまとめておきたいと思います。また、その際に注意点も発見したので整理しておきます。
ファイルの存在チェック
ファイルを作成する処理を書いていると保存前に同名のファイルの存在チェックをしたい場合がありますよね。まずは、その方法です。短いコードですが関数化しました。
Function xIsExists(ByVal vsFilePath As String) As Boolean Dim s As String s = Dir$(vsFilePath) xIsExists = (s <> "") End Function |
引数に調べたいファイル名(フルパス)で指定します。存在する場合 True、存在しない場合 False を返します。
仕組みは単純で Dir ステートメントを使用しているだけです。DOS コマンドの Dir コマンドに似ていて引数に合致するファイルがあれば、そのファイル名を返します。フルパスを引数で指定しても、戻り値はファイル名だけとなります。何らかの戻り値があればファイルが存在することになります。
Dir ステートメントの戻り値は Variant です。Dir$ とすると戻り値を文字列に固定できます。今回は文字列の方がよいので Dir$ を使用しています。
補足ですが、以下の部分を疑問に思われる方がいるかもしれません。
xIsExists = (s <> "") |
If 文で見かける比較があります。<> などの比較演算子は比較した結果を True か False で返します。If 文はこの結果を使って分岐を実現していますが、ここでは True か False を返す機能をそのまま利用しています。ちなみに、( ) でくくらないと文法エラーとなりますので注意してください。
ファイルの一覧の取得
続いてはフォルダ内にどのようなファイルがあるか調査する方法です。
例えば、C:\ に 1.txt、2.txt、3.txt を 3 つのテキストファイルがあったとします。以下のプログラムを実行すると、1.txt が変数 s にセットされます。
s = Dir$("c:\*.txt") |
この状態で Dir を引数なしで実行すると 2.txt が返ってきます。条件を省略すると次のファイルを返してくれるという仕組みになっています。
s = Dir$() |
この機能を利用して、戻り値が空になるまで繰り返すとフォルダ内のファイルの一覧が取得できます。例えば、以下のプログラムはノーツのデータディレクトリ内の domino\icons フォルダの gif ファイルを順に取得する処理です。
Dim s As String Dim v As Variant '調査フォルダ取得 s = ns.GetEnvironmentString("Directory", True) 'データディレクトリ v = Split(s, "\") ReDim Preserve v(UBound(v)+2) v(UBound(v)-1) = "domino" v(UBound(v)) = "icons" s = Join(v, "\") & "\" 'gifファイルを順に取得 Dim sGif As String sGif = Dir$(s & "*.gif", 0) While Not(sGif = "") ・・・gifファイルの処理を記述・・・ '次のファイル sGif = Dir$() Wend |
問題発生 !?
この 2 つの機能を利用して使用して、アプリを作成していたのですが、ある時突然アプリが正常に動作しなくなりました。1 つ目のファイルだけ取得でき、2 つ目以降のファイルが取得できなくなるという症状でした。
この現象の発生は、gif ファイルの処理を改造したタイミングで、ファイルを保存する際に存在チェックを行った(xIsExists 関数をコールした)直後からでした。
そうなんです。Dir ステートメントで次のファイルを取得する機能は、最後に実行した Dir の条件を使用してしまいます。xIsExists 関数をコールしたことにより Dir の条件が更新され、While ループに戻り、sGif = Dir$() を実行したときには、もう gif のことは忘れていたということです。なかなか潔いステートメントですね。
まとめ
今回、この問題は過去の作成したライブラリの内部で Dir ステートメントを使用していたため発生しました。ずいぶん前のコーディングだったので、発見が遅れました。
この問題って、グローバル変数を使った時に発生する弊害に近しいですよね。
ライブラリ開発においては、グローパル変数を使用しないなど独立性が下がらないよう意識しています。ライブラリ内でこのステートメントを使うと外部のプログラムに影響を与え、同様の課題をはらみます。ライブラリなど再利用する部品で、使わないほうがよいですね。
0 件のコメント:
コメントを投稿