加快非现有网络共享的 File.Exists 速度
我必须检查一组文件路径是否代表现有文件。
它工作正常,除非路径包含不在当前网络上的计算机上的网络共享。 在这种情况下,需要相当长的时间(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;
}
此解决方案避免了每次尝试都需要一个线程,首先检查哪些驱动器是可以访问并将其存储在某个地方。
专家交流解决方案:
首先,您可以在 IsDriveReady 函数中设置一个“超时”值。 我将其设置为 5 秒,但可以将其设置为适合您的任何值。
使用以下3种方法:
- 第一个是 WNetGetConnection API 函数,用于获取 驱动器的 UNC (\servername\share)
- 第二个是我们的主要方法:Button1_Click 事件
- 第三个是 IsDriveReady 函数,用于 ping 服务器。
这对我来说非常有用! 给你:
'此 API 函数将用于获取驱动器的 UNC 私有声明函数 WNetGetConnection Lib“mpr.dll”别名 _ “WNetGetConnectionA”_ (ByVal lpszLocalName 作为字符串,_ ByVal lpszRemoteName 作为字符串,_ ByRef cbRemoteName 作为 Int32) 作为 Int32 '这只是一个按钮单击事件 - 将代码添加到适当的事件中 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 处理 Button1.Click Dim bIsReady As Boolean = False 对于每个 dri 作为 IO.DriveInfo In IO.DriveInfo.GetDrives() '如果驱动器只是网络驱动器,则对其执行 ping 操作以查看其是否已准备好。 如果 dri.DriveType = IO.DriveType.Network 那么 '获取 UNC (\\服务器名称\共享) ' dri.Name 返回的驱动器号 暗淡 UNC 作为字符串 = 空格(100) WNetGetConnection(dri.Name.Substring(0, 2), UNC, 100) '假设驱动器已映射 \\servername\share ' 从 UNC 中解析出服务器名 调暗服务器作为字符串 = _ UNC.Trim().Substring(2, UNC.Trim().IndexOf("\", 2) - 2) 'Ping 服务器以查看其是否可用 bIsReady = IsDriveReady(服务器) 别的 bIsReady = dri.IsReady 万一 '只处理准备好的驱动器 如果 bIsReady = True 那么 '处理你的驱动器... MsgBox(dri.Name & "已准备好:" & bIsReady) 万一 下一个 MsgBox("所有驱动器已处理") 结束子 私有函数 IsDriveReady(ByVal serverName As String) As Boolean Dim bReturnStatus As Boolean = False '*** 在此设置超时 *** 昏暗超时为整数 = 5 '5 秒 将 pingSender 调暗为新 System.Net.NetworkInformation.Ping() 暗淡选项作为新的 System.Net.NetworkInformation.PingOptions() 选项.DontFragment = True '输入有效的IP地址 Dim ipAddressOrHostName As String = serverName 暗淡数据作为字符串=“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa” 调暗缓冲区 As Byte() = System.Text.Encoding.ASCII.GetBytes(data) 昏暗回复为 System.Net.NetworkInformation.PingReply = _ pingSender.Send(ipAddressOrHostName,超时,缓冲区,选项) 如果reply.Status = Net.NetworkInformation.IPStatus.Success 那么 b返回状态 = True 万一 返回 bReturnStatus 结束功能
I have to check if a set of file paths represent an existing file.
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.
Questions
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)
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)
UPDATE: Using Threads work, not particularly elegant, though
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;
}
This solution avoids the need for a thread per attempt, first check which drives are reachable and store that somewhere.
Experts exchange solution:
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.
3 methods are used below:
- The first is the WNetGetConnection API function that gets the
UNC (\servername\share) of the drive- The second is our main method: The Button1_Click event
- The third is the IsDriveReady function that pings the server.
This worked great for me! Here you go:
'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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
简而言之,
UNC
名称。ping
驱动器。编辑有关 Bill 的评论
如果 Google 不是引用者,EE 不会免费显示答案。 EE 的链接没有帮助。
OP 找到了我在原始答案中提到的文章,并且很友善地包含了 他的问题的解决方案的源代码。
In a nutshell
UNC
name.ping
the drive.Edit regarding Bill's comment
if Google is not the referer, EE doesn't show the answer for free. Links to EE are not helpful.
OP found the article I've mentioned in my original answer and was kind enough to include the source code for the solution to his question.
另一个“线程解决方案”:
来源:http://www.jonathanantoine。 com/2011/08/18/faster-file-exists/
有人担心“驱动器响应不够快”,所以这是速度和“真相”之间的折衷。 如果你想100%确定,就不要使用它。
Another "thread solution":
Source: http://www.jonathanantoine.com/2011/08/18/faster-file-exists/
There are some concerns about "drive not responding fast enough", so this is compromise between speed and "the truth". Don't you use It if you want to be sure 100%.
使用线程进行检查。 我认为线程可能会超时。
Use Threads to do the checks. I think that threads can be timed out.
这对我来说非常有用!
这是 C# 中的 IsDriveReady():
This worked GREAT for me!
Here's IsDriveReady() in C#:
我发现带有线程超时功能的 pathExists 很有用,但最终意识到它需要从 File.Exists 更改为 Directory.Exists 才能正常工作。
I found the pathExists with thread timeout function useful but finally realized that it needed a change from File.Exists to Directory.Exists to work correctly.
另一种解决方案是使用 CancellationToken
Also another solution is to use CancellationToken
难道您不能仅使用 FileMonitor 控件来实现此目的,以便在删除该控件时触发事件吗? 然后你可以将bool设置为false;
Couldn't you just use FileMonitor control for this so that an event fires when it gets removed? Then you can set bool to false;