0

サーバー上の Uri パスから zip ファイルを収集する Windows サービスを作成しています。私が直面している問題は、サービスがそれを収集しようとしたときに、zip ファイルがまだサーバーに書き込まれていることです。Thread.Sleep(15000)ファイルをダウンロードするための呼び出しを行う前にa を配置すると、正常に動作します。ビデオ アラームを処理する場合、その遅延は許容できません。可能であれば、while ループにチェックを追加して、ダウンロード関数を呼び出す前にサーバー URI からファイルをダウンロードする準備ができているかどうかを確認したいと思います。これは可能ですか?

非同期 WebClient を使用して zip ファイルをダウンロードしています。

internal void DownloadZippedFile(string eventId)
{
    try
    {
        Logger.LogInformation("Extracing Video for event: " + eventId);

        using (WebClient webClient = new WebClient())
        {
            string urlPath = sureViewZipHost + "/archiveevent?user=" + sureViewUserId + "&password=" + sureViewPassword + "&event=" + eventId;
            string tempPath = Path.GetTempPath();

            long lReceived = 0;
            long lTotal = 0;

            webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
            webClient.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
            {
                Logger.LogInformation("downloaded {0} of {1} bytes. {2}% complete", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage);

                // Assign to outer variables to allow busy-wait to check.
                lReceived = e.BytesReceived;
                lTotal = e.TotalBytesToReceive;
            };
    
            webClient.DownloadFileAsync(new Uri(urlPath), tempPath + "//" + eventId + ".zip",eventId);
        }
    }
    catch (Exception ex)
    {
        Logger.LogError("Error extracting Video " + ex.Message);
    }
}

上記のコードを使用して例外がスローされることはありません。部分的にダウンロードした zip を開くと、問題が見つかりました。含まれているものは次のとおりです。

400不正な要求

System.IO.IOException: 別のプロセスで使用されているため、プロセスはファイル 'C:\FileStore\G98\E16884\R6507679\JpegBackup022620132102384484.zip' にアクセスできません。

4

3 に答える 3

1

基本的にはできません-書き込み用にファイルを開こうとする必要があり、例外が発生した場合は書き込みできません:(

最初に別のチェックを行うことができたとしても、書き始める前に結果が古くなっている可能性があります。後で例外が発生する可能性があります。

次のようなことを試すことができます:

public class FileManager
{
    private string _fileName;

    private int _numberOfTries;

    private int _timeIntervalBetweenTries;

    private FileStream GetStream(FileAccess fileAccess)
    {
        var tries = 0;
        while (true)
        {
            try
            {
                return File.Open(_fileName, FileMode.Open, fileAccess, Fileshare.None); 
            }
            catch (IOException e)
            {
                if (!IsFileLocked(e))
                    throw;
                if (++tries > _numberOfTries)
                    throw new MyCustomException("The file is locked too long: " + e.Message, e);
                Thread.Sleep(_timeIntervalBetweenTries);
            }
        }
    }

    private static bool IsFileLocked(IOException exception)
    {
        int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
        return errorCode == 32 || errorCode == 33;
    }

    // other code

}

これは、このような問題を克服するためにコードで使用するものです..

于 2013-02-27T16:53:31.423 に答える
0

サーバー上のプロセスがファイルにアクセスする前にファイルを使用しているかどうかを確認する方法はないと思います。あなたができることは、その400エラーを具体的にキャッチし、「別のプロセスによって使用されている」というエラーメッセージを確認してから、再試行する前に少しスリープすることです。

try
{
  int retrysLeft = 10;
  while (retrysLeft >= 0)
  {
     try 
     {
        // attempt to download
        retrysLeft = -1;
     }
     catch (WebException ex)
     {
        if (ex.InnerException.Message.Contains("used by another process"))
        {
           retrysLeft--;
           Thread.Sleep(1000);
        }
        else throw;
     }
   }
 }
 catch (Exception ex)
 {
    // Regular error handling
 }
于 2013-02-27T16:55:06.210 に答える
0

これを攻撃する 1 つの方法は、(最大再試行回数を指定して) n 秒ごとに操作を再試行することです。

于 2013-02-27T16:53:26.487 に答える