2009-09-17 4 views
12

używamSzybsze działanie DirectoryExists?

DirectoryExists (const PathName : String); 

aby sprawdzić, czy katalog jest osiągalny z komputera czy nie. Ale jeśli katalog nie istnieje, a nazwa ścieżki jest ścieżką sieciową, tj. , metoda ta wymaga bardzo długiego czasu.

Musi istnieć szybszy sposób określenia, że ​​folder sieciowy jest niedostępny. Czy mogę skonfigurować parametr timeout, który DirectoryExists używa wewnętrznie (zajrzałem do kodu źródłowego, ale to właśnie przekazuje do GetFileAttributes, który jest zdefiniowany w kernel32)?

Wszelkie pomysły?

+0

Czy problem jest związany z tym, że katalog nie istnieje na komputerze zdalnym lub że nie można połączyć się z komputerem zdalnym? –

+0

Może być oba, ale w większości przypadków nie mogę się połączyć. – jpfollenius

+0

Jako kontrprzykład chciałbym przedstawić mój mały NAS w domu: kiedy nie używam go przez jakiś czas, dyski się obracają. Kiedy pierwszy raz uzyskuję dostęp do zamontowanego katalogu, zwykła lista może zająć około 20 sekund. W ciągu tych 20 sekund nie można ustalić, czy dany katalog istnieje. Nawet po 15 sekundach nie można mieć pewności, że nie istnieje ... tylko wtedy, gdy otrzymasz faktyczną (negatywną) odpowiedź od hosta, możesz mieć pewność, że plik nie istnieje. –

Odpowiedz

18

Nie ma szybszy sposób:

dowolnej funkcji dostępu zdalnego nic na akcję będzie limitu czasu, gdy udział ten nie jest dostępny.

Jeśli przyczyna twoich limity czasu jest automatyczne odłączanie akcji, a następnie ten link może pomóc: http://support.microsoft.com/default.aspx?scid=kb;[LN];Q138365

Jeśli aplikacja może kontynuować bez zakończeniu kontroli, a następnie można umieścić czek w osobnym wątku , a po zakończeniu kontroli możesz zaktualizować swój status w interfejsie użytkownika.

--jeroen

5

Jeśli testujesz wiele katalogów, powinieneś używać wątków, aby wykonywać wszystkie zapytania równolegle, ponieważ dla udziałów sieciowych są to zazwyczaj długie limity czasu.

+0

Nie testuję zbyt wielu katalogów. Tylko dla jednego. Ale DirectoryExists może zająć około 30 sekund na zwrot, co jest denerwujące. – jpfollenius

6

Nie było to samo pytanie dla C#: How to avoid network stalls in GetFileAttributes?

Jak codymanix powiedział, stosowanie nici. Powyższy link pokaże Ci, jak możesz to zrobić z delegatami w C#. Nie znam Delphi, ale może wiesz, jak przekonwertować kod?

+3

(wątki będą pomocne tylko wtedy, gdy możesz zrobić coś równolegle.) Jeśli następna czynność zależy od udziału (np. W przypadku ładowania konfiguracji), w wątku masz tylko możliwość pokazania użytkownikowi jakiegoś ruchu, to nie przyśpieszyć) –

3

Jest to najlepszy sposób. Możesz dodać kod do wysłania polecenia ping do maszyny, aby upewnić się, że istnieje, ale to pozostawia rutynową awarię, ponieważ wiele komputerów ma dziś zapory programowe skonfigurowane tak, aby ignorować żądania ping, a także możliwość, że żądany udział nie istnieć.

Również na niektórych komputerach, jeśli ścieżka UNC znajduje się na komputerze lokalnym, a lokalna maszyna nie ma aktywnej karty sieciowej (laptop z odłączonym Wi-Fi na przykład w trybie "Samolot"), wówczas żądania UNC również nie będą działać .

0

Jeśli oba komputery znajdują się w tej samej domenie, przyspieszą operacje na plikach podczas obsługi udziałów.

1

W podobnej sytuacji, jak zaleciłeś, dodałem najpierw ping ICMP do serwera. Jeśli serwer nie odpowiada na polecenie ping, zakładam, że jest wyłączony. Możesz zdecydować, który limit czasu ma zostać użyty na pingu samemu, więc możesz ustawić go znacznie krócej niż limit czasu użyty wewnętrznie przy próbie otwarcia udziału pliku.

2

używam następujący kod ...

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; 
    } 
} 

... co pozwala mi mieć wersję limitu czasu Directory.Exist. Nazywam to czymś takim jak ...

bool a = DirectoryExistsTimeout("\\\\machine\\folder", 5000); 

Czy będzie to w porządku dla Ciebie?


Aby być bezpiecznym/legalnym, należy wywołać "callback.EndInvoke (result);" ale wywołanie go blokuje się do zakończenia asynchronizacji, więc to pokonuje obiekt kodu. Być może trzeba to zrobić pod koniec kodu - może wyjść?