Speed up File.Exists for non existing network shares
我必须检查一组文件路径是否代表现有文件。
它工作正常,除非路径包含不在当前网络上的计算机上的网络共享。在这种情况下,超时需要相当长的时间(30 或 60 秒)。
问题
-
有没有办法缩短非现有网络共享的超时时间? (我敢肯定,当它们确实存在时,它们会迅速回答,所以 1 秒的超时就可以了)
-
有没有其他方法可以在不开始缓存并使算法更复杂的情况下解决这个问题? (即,我已经知道这些 X 网络共享不存在,跳过其余匹配路径)
更新:使用线程工作,虽然不是特别优雅
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
这个解决方案避免了每次尝试都需要一个线程,首先检查哪些驱动器可以访问并将其存储在某个地方。
专家交流解决方案:
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 driveThe 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 '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
简而言之
编辑关于比尔的评论
如果 Google 不是推荐人,EE 不会免费显示答案。指向 EE 的链接没有帮助。
OP 找到了我在原始答案中提到的文章,并且非常友好地提供了解决他问题的源代码。
另一个"线程解决方案":
1 2 3 4 5 6 7 8 9 10 11 | /// <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%,请不要使用它。
使用线程进行检查。我认为线程可以超时。
这对我来说非常有用!
这是 C# 中的 IsDriveReady():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } |
我发现带有线程超时功能的 pathExists 很有用,但最终意识到它需要从 File.Exists 更改为 Directory.Exists 才能正常工作。
您不能为此使用 FileMonitor 控件,以便在删除事件时触发事件吗?然后你可以将 bool 设置为 false;