我使用
DirectoryExists (const PathName : String);
检查计算机是否可以访问目录。但是,如果该目录不存在且路径名为网络路径,则需要进行其他步骤。
\\computer1\Data
该方法返回所需时间过长。
肯定有更快的方法可以确定网络文件夹是否不可达。或者我可以配置一些超时参数,让DirectoryExists在内部使用(我查看了源代码,但它只是委派给定义在kernel32中的GetFileAttributes)?
有什么想法吗?
我使用
DirectoryExists (const PathName : String);
检查计算机是否可以访问目录。但是,如果该目录不存在且路径名为网络路径,则需要进行其他步骤。
\\computer1\Data
该方法返回所需时间过长。
肯定有更快的方法可以确定网络文件夹是否不可达。或者我可以配置一些超时参数,让DirectoryExists在内部使用(我查看了源代码,但它只是委派给定义在kernel32中的GetFileAttributes)?
有什么想法吗?
没有比这更快的方式:
任何访问远程共享的功能都会在该共享不可用时超时。
如果您的超时原因是共享自动断开连接,则以下链接可能会对您有所帮助:
如果应用程序可以在检查完成之前继续运行,则可以将检查放在一个单独的线程中,并在检查完成后更新UI上的状态。
请注意,当您尝试使用多线程方式时,必须证明您的代码没有竞争条件和内存泄漏。超时与异常结合通常会使这成为一项艰巨的任务。
有一个与 C# 相同的问题:
如何避免 GetFileAttributes() 函数中的网络停顿?
正如 codymanix 所说,使用线程。上面的链接将向您展示如何在 C# 中使用委托完成此操作。不知道 Delphi,但也许您知道如何转换代码?
private delegate bool DirectoryExistsDelegate(string folder);
bool DirectoryExistsTimeout(string path, int millisecondsTimeout)
{
try
{
DirectoryExistsDelegate callback = new DirectoryExistsDelegate(Directory.Exists);
IAsyncResult result = callback.BeginInvoke(path, null, null);
if (result.AsyncWaitHandle.WaitOne(millisecondsTimeout, false))
{
return callback.EndInvoke(result);
}
else
{
callback.EndInvoke(result); // Needed to terminate thread?
return false;
}
}
catch (Exception)
{
return false;
}
}
...这让我能够拥有一个Directory.Exist的超时版本,我会像这样调用它...
bool a = DirectoryExistsTimeout("\\\\machine\\folder", 5000);
这对您的需求来说可以吗?
为了安全/合法,您需要调用 "callback.EndInvoke(result);" 但是调用它会锁定直到异步完成,这违背了代码的初衷。也许这需要在您的代码结尾处完成 - 退出可能是一个好选择。
NetDirectoryExists(Path, Timeout)
。它使用了线程,并且是TDirectory.Exists(Path)
的完美替代品。
Usage:
if NetDirectoryExists('\\computer1\Data', 1000) then ...
if NetDirectoryExists('C:\Folder', 500) then ...
If the Folder exists, the function needs only some milliseconds, same with not existing folders (C:\NotExisting
). If it is a not reachable network path (\\ServerNotReady\C$
) then it will consume the number of milliseconds given by the second parameter.
Function NetDirectoryExists( const dirname: String;
timeoutMSecs: Dword ): Boolean;
implementation
uses
Classes, Sysutils, Windows;
type
ExceptionClass = Class Of Exception;
TTestResult = (trNoDirectory, trDirectoryExists, trTimeout );
TNetDirThread = class(TThread)
private
FDirname: String;
FErr : String;
FErrclass: ExceptionClass;
FResult : Boolean;
protected
procedure Execute; override;
public
Function TestForDir( const dirname: String;
timeoutMSecs: Dword ):TTestResult;
end;
Function NetDirectoryExists(
const dirname: String; timeoutMSecs: Dword ): Boolean;
Var
res: TTestResult;
thread: TNetDirThread;
Begin
Assert( dirname <> '', 'NetDirectoryExists: dirname cannot be empty.' );
Assert( timeoutMSecs > 0, 'NetDirectoryExists: timeout cannot be 0.' );
thread:= TNetDirThread.Create( true );
try
res:= thread.TestForDir( dirname, timeoutMSecs );
Result := res = trDirectoryExists;
If res <> trTimeout Then
thread.Free;
{Note: if the thread timed out it will free itself when it finally
terminates on its own. }
except
thread.free;
raise
end;
End;
procedure TNetDirThread.Execute;
begin
try
FResult := DirectoryExists( FDirname );
except
On E: Exception Do Begin
FErr := E.Message;
FErrclass := ExceptionClass( E.Classtype );
End;
end;
end;
function TNetDirThread.TestForDir(const dirname: String;
timeoutMSecs: Dword): TTestResult;
begin
FDirname := dirname;
Resume;
If WaitForSingleObject( Handle, timeoutMSecs ) = WAIT_TIMEOUT
Then Begin
Result := trTimeout;
FreeOnTerminate := true;
End
Else Begin
If Assigned( FErrclass ) Then
raise FErrClass.Create( FErr );
If FResult Then
Result := trDirectoryExists
Else
Result := trNoDirectory;
End;
end;
在类似于你所描述的情况下,我首先向服务器添加了一个ICMP ping。如果服务器没有响应ping,则我认为它已经宕机。您可以自行决定ping的超时时间,因此可以将其设置得比尝试打开文件共享时内部使用的超时时间短得多。