Acelerar Archivo.Existe para recursos compartidos de red no existentes


Tengo que comprobar si un conjunto de rutas de archivo representan un archivo existente.

Funciona bien excepto cuando la ruta contiene un recurso compartido de red en una máquina que no está en la red actual. En este caso, se necesita un tiempo bastante largo (30 o 60 segundos) para que el tiempo de espera.

Preguntas

  • ¿Hay alguna manera de acortar el tiempo de espera para los recursos compartidos de red no existentes? (Estoy seguro de que cuando existan responderán rápidamente, por lo que un tiempo de espera de 1 segundo sería fine)

  • ¿Hay alguna otra manera de resolver este problema sin comenzar a almacenar en caché y hacer que el algoritmo sea más complejo? (es decir, ya sé que estos recursos compartidos de red X no existen, omita el resto de las rutas coincidentes)

ACTUALIZACIÓN: El uso de hilos de trabajo, no particularmente elegante, aunque

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

Esta solución evita la necesidad de un subproceso por intento, primero verifique qué unidades son accesibles y guárdelas en algún lugar.


Intercambio de expertos solución:

En primer lugar, hay un valor de "tiempo de espera" que puede establecer en la función IsDriveReady. Lo tengo configurado por 5 segundos, pero lo puse para lo que funcione para ti.

3 métodos se utilizan a continuación:

  1. La primera es la función API de WNetGetConnection que obtiene UNC (\servername\share) de la unidad
  2. El segundo es nuestro método principal: El evento button1_Click
  3. La tercera es la función IsDriveReady eso hace sonar al servidor.

Esto funcionó muy bien para mí! Aquí tienes:

'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 & " is ready:  " & 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
Author: Wai Ha Lee, 2009-08-05

6 answers

Use Hilos para hacer las comprobaciones. Creo que los hilos pueden ser temporizados.

 4
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-05 12:58:19

En pocas palabras

  1. Construya una lista de unidades disponibles.
  2. Intente resolver el driveletter a un nombre UNC.
  3. Intenta ping la unidad.

Editar sobre el comentario de Bill

si Google no es el referente, EE no muestra la respuesta de forma gratuita. Los enlaces a EE no son útiles.

OP encontró el artículo que he mencionado en mi respuesta original y tuvo la amabilidad de incluir el código fuente para la solución a su pregunta.

 7
Author: Lieven Keersmaekers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:08

¡Esto funcionó muy bien para mí!
Aquí está IsDriveReady() en C#:

using System.Net;
private bool IsDriveReady(string serverName)
{
   // ***  SET YOUR TIMEOUT HERE  ***     
   int timeout = 5;    // 5 seconds 
   System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
   System.Net.NetworkInformation.PingOptions options = new System.Net.NetworkInformation.PingOptions();
   options.DontFragment = true;      
   // Enter a valid ip address     
   string ipAddressOrHostName = serverName;
   string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
   byte[] buffer = System.Text.Encoding.ASCII.GetBytes(data);
   System.Net.NetworkInformation.PingReply reply = pingSender.Send(ipAddressOrHostName, timeout, buffer, options);
   return (reply.Status == System.Net.NetworkInformation.IPStatus.Success);
}
 1
Author: dlchambers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-26 22:18:14

Encontré útil la función pathExists with thread timeout, pero finalmente me di cuenta de que necesitaba un cambio desde File.Existe en el directorio.Existe para funcionar correctamente.

 0
Author: user2533239,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-28 20:06:02

Otra "solución de hilo":

/// <sumary>Check if file exists with timeout</sumary>
/// <param name="fileInfo">source</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait,
///  or <see cref="System.Threading.Timeout.Infinite"/> (-1) to wait indefinitely.</param>
/// <returns>Gets a value indicating whether a file exists.</returns>
public static bool Exists(this FileInfo fileInfo, int millisecondsTimeout)
{
    var task = new Task<bool>(() => fileInfo.Exists);
    task.Start();
    return task.Wait(millisecondsTimeout) && task.Result;
}

Fuente: http://www.jonathanantoine.com/2011/08/18/faster-file-exists/

Hay algunas preocupaciones sobre "la unidad no responde lo suficientemente rápido", por lo que esto es un compromiso entre la velocidad y "la verdad". No lo uses si quieres estar seguro al 100%.

 0
Author: Jan 'splite' K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-05 11:15:02

¿No podría simplemente usar el control FileMonitor para esto de modo que un evento se dispare cuando se elimine? A continuación, puede establecer bool a false;

 -1
Author: jay_t55,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-07 18:49:19