代码之家  ›  专栏  ›  技术社区  ›  jpfollenius Rob Kennedy

更快的目录现有功能?

  •  14
  • jpfollenius Rob Kennedy  · 技术社区  · 15 年前

    我用

    DirectoryExists (const PathName : String);
    

    检查是否可以从计算机访问目录。但是如果目录不存在并且路径名是网络路径,即

    \\computer1\Data
    

    该方法需要很长时间才能返回。

    必须有更快的方法来确定无法访问网络文件夹。或者,我可以配置DirectoryExists在内部使用的一些超时参数(我查看了源代码,但它只委托给在kernel32中定义的getfileattributes)?

    有什么想法吗?

    8 回复  |  直到 6 年前
        1
  •  19
  •   Jeroen Wiert Pluimers    6 年前

    没有更快的方法:

    当远程共享不可用时,任何访问远程共享上任何内容的函数都将超时。

    如果超时的原因是共享的自动断开,则这些链接可能会帮助您:

    如果应用程序可以在不完成检查的情况下继续运行,那么您可以将检查放在单独的线程中,完成检查后,您可以在UI中更新您的状态。

    请注意,当您尝试多线程方式时,您必须证明您的代码没有竞争条件和内存泄漏。超时和异常通常会使这项任务变得困难。

        2
  •  6
  •   Community CDub    8 年前

    C也有同样的问题: How to avoid network stalls in GetFileAttributes?

    正如科迪马尼克斯所说,用线。上面的链接将向您展示如何使用C中的代理。不知道Delphi,但也许你知道如何转换代码?

        3
  •  5
  •   codymanix    15 年前

    如果测试大量目录,则应使用线程并行执行所有查询,因为对于网络共享,线程通常超时较长。

        4
  •  3
  •   skamradt    15 年前

    这是最好的方法。您可以向Ping机器添加一些代码以确保它的存在,但这仍然会使程序失败,因为今天有许多计算机设置了软件防火墙来忽略Ping请求,并且请求的共享可能不存在。

    此外,在某些计算机上,如果UNC路径在本地计算机上,并且本地计算机没有活动网卡(例如在“飞行”模式下,Wi-Fi断开的笔记本电脑),则UNC请求也将失败。

        5
  •  2
  •   MKesper    9 年前

    我使用以下代码…

    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);”,但在异步完成之前调用它会锁定,因此这会使代码的对象失效。也许这需要在代码结束时完成-也许退出?

        6
  •  1
  •   Stijn Sanders    15 年前

    在类似于您指定的情况下,我首先向服务器添加了一个ICMP ping。如果服务器没有响应ping,我假设它已关闭。您可以自己决定在Ping上使用哪个超时,因此可以将其设置为比试图打开文件共享时内部使用的超时短得多。

        7
  •  0
  •   pani    15 年前

    如果两台计算机都在同一个域中,那么在处理共享时,它将加速文件操作。

        8
  •  0
  •   Michael Hutter    6 年前

    这个功能对我很有用: NetDirectoryExists(Path, Timeout)
    它使用线程,是 TDirectory.Exists(Path)

    用途:
    if NetDirectoryExists('\\computer1\Data', 1000) then ...
    if NetDirectoryExists('C:\Folder', 500) then ...

    如果文件夹存在,函数只需要几毫秒,与不存在的文件夹相同( C:\NotExisting )如果是不可到达的网络路径( \\ServerNotReady\C$ )然后它将消耗第二个参数给出的毫秒数。

    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;