web-dev-qa-db-ja.com

Fileを高速化します。存在しないネットワーク共有に存在します

ファイルパスのセットが既存のファイルを表しているかどうかを確認する必要があります。

パスに現在のネットワーク上にないマシン上のネットワーク共有が含まれている場合を除いて、正常に機能します。この場合、タイムアウトするまでにかなり長い時間(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つの方法が使用されます。

  1. 1つ目は、ドライブのUNC(\ servername\share)を取得するWNetGetConnectionAPI関数です。
  2. 2番目はメインメソッドです:Button1_Clickイベント
  3. 3つ目は、サーバーに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
34
Vinko Vrsalovic

スレッドを使用してチェックを行います。スレッドがタイムアウトする可能性があると思います。

4
Nick

手短に

  1. 使用可能なドライブのリストを作成します。
  2. ドライブレターをUNC名に解決してみてください。
  3. ドライブをpingしてみてください。

ビルのコメントに関する編集

Googleがリファラーでない場合、EEは無料で回答を表示しません。 EEへのリンクは役に立ちません。

OPは、私が最初の回答で言及した記事を見つけ、彼の質問に ソリューションのソースコード を含めるのに十分親切でした。

7

別の「スレッドソリューション」:

/// <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%確実にしたい場合は使用しないでください。

2
Jan 'splite' K.

これは私にとって素晴らしい働きをしました!
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);
}
1
dlchambers

スレッドタイムアウト関数を使用したpathExistsは便利でしたが、正しく機能するにはFile.ExistsからDirectory.Existsに変更する必要があることにようやく気付きました。

0
user2533239