title: Speed up File.Exists for non existing network shares
body: <p>I have to check if a set of file paths represent an existing file.</p>
  
  <p>It works fine except when the path contains a network share on a machine that's not on the current network. In this case it takes a pretty long time (30 or 60 seconds) to timeout.</p>
  
  <p>Questions</p>
  
  <ul>
  <li><p>Is there a way to shorten the timeout for non existing network shares? (I'm certain that when they do exist they'll answer quickly, so a timeout of 1 sec would be fine)</p></li>
  <li><p>Is there any other way to solve this issue without starting to cache and making the algorithm more complex? (ie, I already know these X network shares don't exist, skip the rest of the matching paths)</p></li>
  </ul>
  
  <p>UPDATE: Using Threads work, not particularly elegant, though</p>
  
  <pre><code>public bool pathExists(string path) 
  {
      bool exists = true;
      Thread t = new Thread
      (
          new ThreadStart(delegate () 
          {
              exists = System.IO.File.Exists(path); 
          })
      );
      t.Start();
      bool completed = t.Join(500); //half a sec of timeout
      if (!completed) { exists = false; t.Abort(); }
      return exists;
  }
  </code></pre>
  
  <p>This solution avoids the need for a thread per attempt, first check which drives are reachable and store that somewhere.</p>
  
  <hr>
  
  <h2><a href="http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22595703.html" rel="noreferrer"><strong>Experts exchange solution</strong></a>:</h2>
  
  <blockquote>
    <p>First of all, there is a "timeout" value that you can set in the IsDriveReady function.  I have it set for 5 seconds, but set it for whatever works for you.</p>
    
    <p>3 methods are used below:</p>
    
    <ol>
    <li>The first is the WNetGetConnection API function that gets the 
              UNC (\servername\share) of the drive</li>
    <li>The second is our main method:  The Button1_Click event</li>
    <li>The third is the IsDriveReady function that pings the server.</li>
    </ol>
    
    <p>This worked great for me!  Here you go:</p>
  
  <pre><code>'This API Function will be used to get the UNC of the drive
  Private Declare Function WNetGetConnection Lib "mpr.dll" Alias _
  "WNetGetConnectionA" _
  (ByVal lpszLocalName As String, _
  ByVal lpszRemoteName As String, _
  ByRef cbRemoteName As Int32) As Int32
  
  
  'This is just a button click event - add code to your appropriate event
  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  
      Dim bIsReady As Boolean = False
  
      For Each dri As IO.DriveInfo In IO.DriveInfo.GetDrives()
  
          'If the drive is a Network drive only, then ping it to see if it's ready.
          If dri.DriveType = IO.DriveType.Network Then
  
              'Get the UNC (\\servername\share) for the 
              '    drive letter returned by dri.Name
              Dim UNC As String = Space(100)
              WNetGetConnection(dri.Name.Substring(0, 2), UNC, 100)
  
              'Presuming the drive is mapped \\servername\share
              '    Parse the servername out of the UNC
              Dim server As String = _
                   UNC.Trim().Substring(2, UNC.Trim().IndexOf("\", 2) - 2)
  
              'Ping the server to see if it is available
              bIsReady = IsDriveReady(server)
  
          Else
              bIsReady = dri.IsReady
  
          End If
  
          'Only process drives that are ready
          If bIsReady = True Then
              'Process your drive...
              MsgBox(dri.Name &amp; " is ready:  " &amp; bIsReady)
  
          End If
  
      Next
  
      MsgBox("All drives processed")
  
  End Sub
  
  Private Function IsDriveReady(ByVal serverName As String) As Boolean
      Dim bReturnStatus As Boolean = False
  
      '***  SET YOUR TIMEOUT HERE  ***
      Dim timeout As Integer = 5    '5 seconds
  
      Dim pingSender As New System.Net.NetworkInformation.Ping()
      Dim options As New System.Net.NetworkInformation.PingOptions()
  
      options.DontFragment = True
  
      'Enter a valid ip address
      Dim ipAddressOrHostName As String = serverName
      Dim data As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
      Dim buffer As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
      Dim reply As System.Net.NetworkInformation.PingReply = _
                  pingSender.Send(ipAddressOrHostName, timeout, buffer, options)
  
      If reply.Status = Net.NetworkInformation.IPStatus.Success Then
          bReturnStatus = True
  
      End If
  
      Return bReturnStatus
  End Function
  </code></pre>
  </blockquote>