16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"FindFirst/FindNext/FindCloseの正しい用法"
この発言に対し以下のコメントが寄せられています
#00771 TOMO さん RE:FindFirst/FindNext/FindCloseの正しい
ディレクトリを走査したり、特定のファイルの属性を取得したり、あるいはファ
イルの存在を高速に検査する方法として FindFirst/FindNext/FindClose のセッ
トがありますが、つい最近、この代表的なサンプルに間違いがあることに気がつ
きました。
たとえば、ある条件にしたがったファイルやフォルダを連続して処理する手順
は、ヘルプの例にも次のように書かれています。
Found := FindFirst(FileOrFolder, Attributes, SRec);
while Found = 0 do
begin
ProcessFileOrFolder(SRec);
Found := FindNext(SRec);
end;
FindClose(SRec);
このコードは、たいていの場合OKなのですが、Attributes に faDirectory が
入っていない場合などに、FindClose でシステムが異常になるケースがありま
す。たとえば空のフォルダの中で通常ファイルを検索しようとする場合に問題が
発生します。
これは、FindFirst 関数に問題があります。FindFirst 内部では、API の
FindFirstFile で正しいハンドルが取得されたら、 FindMatchingFile が呼ばれ
るようになっています。ここでファイルが見つからない場合には、その場で
FindClose を呼び出しているのが原因です。たとえば、FindFirstFile が成功し
た後に FindMatchingFile が ERROR_NO_MORE_FILES を返した場合には、Found
には ERROR_NO_MORE_FILES が返ってきますが、その際、SRec は無効なデータと
なります。すでに FindClose が呼ばれているのに SRec.FindHandle が
INVALID_HANDLE_VALUE とはなっていないためです。あとで、ユーザが
FindClose を呼び出すと API の FindClose が2度呼ばれることになります。こ
こでリソースの漏れや、Windows NT だと、FindClose で CPU タイムが 100% に
張り付いてプロセスがハングする場合があります。
一番いい解決方法は、FindNext と同様に FindFirst 内で FindMatchingFile 後
にエラーが発生しても FindClose を呼び出さないようにライブラリを書き換え
ることです。
2番目は、FindClose の中で FindHandle を解放した後に、FindHandle に
INVALID_HANDLE_VALUE を代入しておくことです。FindClose は FindHandle の
検査をしてから実行するため、これも有効な手です。
ただ、ライブラリの書き換えは、とくに Delphi 3 以降のパッケージの問題も絡
んでくるため難しいため、ユーザサイドのコードで対処するには次のようにしま
す。
Found := FindFirst(FileOrFolder, Attributes, SRec);
if Found = 0 then
begin
repeat
ProcessFileOrFolder(SRec);
Found := FindNext(SRec);
until Found <> 0;
FindClose(SRec);
end;
ワイルドカードを使ったファイルの存在チェックの場合だと、次のようになりま
す。
{ ワイルドカードによるファイルの存在検査 }
function WildFileExists(const WildName:string):Boolean;
var
Rec:TSearchRec;
begin
Result := FindFirst(WildName, faArchive, Rec) = 0;
if Result then
FindClose(Rec);
end;
FindFirst がエラーで戻ったら FindClose を呼ばないのが要点です。ただし、
将来のライブラリのバージョンでは、どうなるかは分かりません。バージョン
アップしたときには SysUtils をチェックすることをお勧めします。
98/8/17(Mon) 00:30pm [AirCraft 97開発] PFF01344 DUDE
Original document by DUDE 氏 ID:(PFF01344)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|