加快非现有网络共享的 File.Exists

Posted

技术标签:

【中文标题】加快非现有网络共享的 File.Exists【英文标题】:Speed up File.Exists for non existing network shares 【发布时间】:2010-11-17 00:07:48 【问题描述】:

我必须检查一组文件路径是否代表现有文件。

它工作正常,除非路径包含不在当前网络上的计算机上的网络共享。在这种情况下,超时需要相当长的时间(30 或 60 秒)。

问题

有没有办法缩短非现有网络共享的超时时间? (我敢肯定,当它们确实存在时,它们会很快回答,所以 1 秒的超时就可以了)

有没有其他方法可以在不开始缓存并使算法更复杂的情况下解决此问题? (即,我已经知道这些 X 网络共享不存在,跳过其余匹配路径)

更新:使用线程工作,但不是特别优雅

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;

此解决方案避免了每次尝试都需要一个线程,首先检查哪些驱动器可以访问并将其存储在某个地方。


Experts exchange solution:

首先,您可以在 IsDriveReady 函数中设置一个“超时”值。我将它设置为 5 秒,但将其设置为适合您的任何内容。

下面使用了3种方法:

    第一个是 WNetGetConnection API 函数,它获取 驱动器的 UNC (\servername\share) 第二个是我们的主要方法:Button1_Click 事件 第三个是 ping 服务器的 IsDriveReady 函数。

这对我来说非常有用!给你:

'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

【问题讨论】:

见***.com/questions/726602/… 是的,我已经投票决定关闭它作为一个骗子。 Chris Pebble 删除了他与问题相关联的答案(我不知道为什么) Expert Exchange 解决方案似乎不太好。文件服务器很可能不响应 ping。这并不意味着它不可用。 @mhenry1384 是的。但是,如果您知道它应该响应 ping,它会很有用。如果您想支持 ping 被阻止,您可以尝试连接到 SMB 端口并查看它是否响应... @Kiquenet 线程解决方案是我这些天倾向于使用的。效率很高。 【参考方案1】:

简而言之

    建立可用驱动器列表。 尝试将驱动器号解析为UNC 名称。 尝试ping驱动器。

修改比尔的评论

如果 Google 不是推荐人,EE 不会免费显示答案。指向 EE 的链接没有帮助。

OP 找到了我在原始答案中提到的文章,并且非常友好地将the source code for the solution 包含在他的问题中。

【讨论】:

专家交流不是我最喜欢的网站。 这不是我的,但谷歌是。答案都在页面下方。链接到原始答案和代码是不正确的 查看尼克回答中的 cmets。 如果 Google 不是推荐人,EE 不会免费显示答案。指向 EE 的链接没有帮助。 @Bill the Lizard,我不知道,谢谢指出。【参考方案2】:

另一种“线程解决方案”:

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

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

有些人担心“驱动器响应不够快”,所以这是速度和“真相”之间的妥协。如果你想确定 100%,就不要使用它。

【讨论】:

【参考方案3】:

使用线程进行检查。我认为线程可以超时。

【讨论】:

(如果它被关闭为骗子或出现更好的选择,将接受) 我一直在思考这个概念,但对我来说,为每个文件检查一个线程似乎有点过头了。您的里程可能会有所不同。 @Lieven:这比让您的应用多花两个数量级的时间来检查文件列表是否存在要好得多。 我非常好奇您在 sexchange 网站上指的是什么方法;) 你可能不知道原域名:expertsexchange.com 选择在哪里分词。【参考方案4】:

这对我来说非常有用! 这是 C# 中的 IsDriveReady():

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

【讨论】:

真实故事:IT 部门在某些企业云文件存储上关闭了 ping。是的。它破坏了很多东西,但他们拒绝打开它,因为“原因”。【参考方案5】:

我发现带有线程超时功能的 pathExists 很有用,但最终意识到它需要从 File.Exists 更改为 Directory.Exists 才能正常工作。

【讨论】:

【参考方案6】:

您不能为此使用 FileMonitor 控件,以便在删除事件时触发事件吗?然后你可以将bool设置为false;

【讨论】:

不,该应用程序仅运行以检查数据库中的文件列表是否存在。

以上是关于加快非现有网络共享的 File.Exists的主要内容,如果未能解决你的问题,请参考以下文章

Windows 服务无法访问网络共享 [关闭]

File.exists() 为现有文件返回 false

solaris 10,java 6,file.exists 看不到现有文件

网络运维——访问共享的三种方式

File.Exists仅在文件名上返回true

如何使进度条加快