0

我正在编写一个 Windows 服务,它从服务器上的 Uri 路径收集一个 zip 文件。我遇到的问题是当我的服务尝试收集压缩文件时,它仍在服务器上被写入。如果我Thread.Sleep(15000)在打电话下载文件之前放了一个,它工作正常。处理视频报警时,这种延迟是不可接受的。如果可能的话,我希望在调用下载函数之前在 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

解决此问题的一种方法是每 n 秒重试一次操作(指定最大重试次数)。

于 2013-02-27T16:53:26.487 回答
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 回答