Windows 7 でネットワーク上のファイルの認識が遅い

解決


mbr  2012-06-09 22:57:56  No: 42451  IP: 192.*.*.*

Delphi 2007 でプログラムしております。LAN接続された2台のPCを使って、一方のPCからFileExists関数を250m秒間隔でコールして他方のPC上に特定のファイルが存在するようになるまで監視し、存在が確認できたらそのファイルを読みに行くという処理をしております。Windows 7とXPやVistaの組み合わせではまったく問題がないのですが、2台ともWindows 7の場合に限り、実際にファイルが存在してからFileExists関数がTrueを返すまでに5秒ほどかかります。すでに存在しているファイルであれば一発でTrueが返ってきますが、今作ったばかりのファイルはエクスプローラにそのファイル名が表示されてから5秒くらいたたないとFileExists関数がTrueになりません。FileAge, FileGetAttr などの関数も同じです。強引にオープンしようとしてもエラーになります。Windows 7側の設定の何かを変更する必要がありそうなのですが、何か情報はないでしょうか?  XP互換モードでの実行、ファイアーウォールをオフにする、アンチウイルスをオフにする、このあたりは試してみましたがだめでした。

編集 削除
Mr.XRAY  2012-06-10 00:12:32  No: 42452  IP: 192.*.*.*

こんにちは,

関係あるかどうか,また参考になるどうか分かりませんが,最近こんなのが
話題になっていました.
http://mrxray.on.coocan.jp/bbs/DelphiBBS/mrxray_delphifan_coffe.cgi?tree=s5995#5995

また,VMwareの設定ですが,ネット上の情報では,一般のLANでも有効であるような記事
を見たことがあります.
http://mrxray.on.coocan.jp/Delphi/Others/VmwareLAN.htm

最初の認識が遅いかも知れないので,転送速度ではなく,違う原因かも知れません.

編集 削除
mbr  2012-06-10 00:37:47  No: 42453  IP: 192.*.*.*

Mr.XRAYさん、ありがとうございます。
状況がもう少し判明しましたので記しておきます。
ファイルが作成された直後に1回目のFileExists関数を呼ぶとすぐにTrueが返ります。しかしファイルが作成される以前から何回かFileExists関数を呼んでFalseが返ってきている状態でファイルが作成されると、その後5秒間ほどはTrueになりません。ファイルが存在しないという情報がどこかにキャッシュされていて、実際にファイルが存在するようになってもしばらくはキャッシュの値が返されているような、そんな挙動です。

編集 削除
Mr.XRAY  2012-06-10 01:05:04  No: 42454  IP: 192.*.*.*

なるほど,転送速度関係とは関係ないようですね.
Windows 7 のファイルアクセス特有の問題かな?

一度,FileExists関数ではなく,FindFirstFile 関数などで単独調査してみる,というのはどうでしょう.
ちょっと,現在の私の手には負えそうもないです.スミマセン.

編集 削除
mbr  2012-06-10 01:13:50  No: 42455  IP: 192.*.*.*

FindFirstも試しましたが同じでしたね。

編集 削除
Nov  2012-06-10 01:41:50  No: 42456  IP: 192.*.*.*

こんばんわ
質問の回答にはなってませんが、
>FileExists関数を250m秒間隔でコール
ということなら、FindFirstChangeNotificationとかでは駄目ですか。

編集 削除
mbr  2012-06-10 17:29:00  No: 42457  IP: 192.*.*.*

Novさん、ヒントをありがとうございます。簡単なテストプログラムで試して見たところファイルが生成される瞬間をとらえることができました。これはうまくいくかもと期待して実際のプログラムの一部に試験的に組み込んでみましたがうまくいきません。

原因はFindFirstChangeNotificationを呼ぶ前に目的のファイルがすでに存在しているかどうか確認するため1回FileExists関数を呼ぶ必要があり、ディレクトリ内容の変更を検知した後はその検知が目的のファイルが生成されたものであるかどうかを確認するため再度FileExists関数を呼ぶ必要があります。この2回目のFileExistsがTrueを返しません。

検知前のFileExistsを呼ばないようにすれば検知後のFileExistsはTrueを返します。1回FileExists関数を呼んでFalseが返るとその後5秒間ぐらいはFalseを返し続けるようです。1回目のFileExistsをFileAgeや FileGetAttrに代えても同じです。

編集 削除
mb  2012-06-10 17:59:18  No: 42458  IP: 192.*.*.*

素人考えで恐縮ですが、ファイルを実際に開くなどできるか試してみては
どうでしょうか。ファイルが存在しなければ開けないわけですし。

編集 削除
mbr  2012-06-10 19:02:09  No: 42459  IP: 192.*.*.*

FileExists関数がFalseを返す状況では強引にファイルをオープンしようとしてもエラーになります。エクスプローラで他のPC上の共有フォルダをのぞくとそのファイルは存在していますが5秒ほどたたないとオープンできません。

編集 削除
Nov  2012-06-10 21:20:42  No: 42460  IP: 192.*.*.*

>FileExistsがTrueを返しません
これは、例えば、FileSystemObject(Oleオブジェクト)のFileExistsでも同じでしょうか(内部的にAPIと同じルーチンを使っていたら駄目かもしれませんが)?

編集 削除
mbr  2012-06-11 00:22:15  No: 42461  IP: 192.*.*.*

解決しました。
MicrosoftのSMB2プロトコルが「ファイルが存在しない」という情報を長時間キャッシュしたままにしているのが原因のようです。詳しくは

http://support.microsoft.com/kb/2537777/ja

レジストリキー HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters に FileNotFoundCacheLifetime=0 を追加すればキャッシュを無効にできます。単位は秒ですのでデフォルトで5くらいになっているのでしょう。

Microsoftはバグと認識している(?)ようですので SP2 では解消してほしいですね。

編集 削除