如何在下载前检查zip文件是否未被其他进程使用

本文关键字:其他 进程 是否 文件 下载 zip 检查 | 更新日期: 2023-09-27 18:01:30

我正在编写一个Windows服务,从服务器上的Uri路径收集zip文件。我遇到的问题是,当我的服务试图收集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 BadRequest

先。IOException:进程无法访问该文件"C: ' FileStore ' G98 ' E16884 ' R6507679 ' JpegBackup022620132102384484.zip"因为它正在被其他进程使用。

如何在下载前检查zip文件是否未被其他进程使用

你不能,基本上-你必须尝试打开文件进行写入,如果你得到一个异常,你不能写入它:(

即使你可以先做一个单独的检查,结果也会在你开始写之前过期——你以后仍然可能以异常结束。

你可以试试这样做:

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
}

这是我在我的代码中使用的,以克服这样的问题。

攻击的一种方法是每n秒重试一次操作(指定重试的最大次数)。

我认为在试图访问文件之前,没有任何方法可以检查服务器上的进程是否正在使用文件。你可以做的是专门捕获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
 }