IOException由访问仍在移动的文件引起

时间:2018-10-12 08:51:44

标签: c# .net

我有一个解决方案,可以充当两个系统之间的接口,读取放置在FTP站点上的文件并导入所有订单/产品/等。进入目标系统。

拾取文件后,将其移到相同位置的临时文件中,然后将内容读取到XmlDocument中。

string[] files = Directory.GetFiles(pickupFolder, fileFilter, SearchOption.TopDirectoryOnly);
foreach (string pathToFile in files)
{
  FileInfo srcFile = new FileInfo(pathToFile);
  string tmpFilename = Path.Combine(srcFile.DirectoryName, $"~{Path.GetFileNameWithoutExtension(srcFile.Name)}.tmp");
  srcFile.MoveTo(tmpFilename);

  XmlDocument srcXml = new XmlDocument();
  try
  {
    using (FileStream fs = srcFile.Open(FileMode.Open, FileAccess.Read))
    {
      srcXml.Load(fs);
    }
  }
  catch (XmlException ex)
  {
    throw new FileException($"Invalid XML in {srcFile.Name}.", ex);
  }
}

非常偶尔,界面会尝试打开文件,以便在移动过程尚未完成时将其加载到XmlDocument中,并抛出IOException。有什么方法可以防止这种情况发生?

创建需要迭代并处理文件的东西的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

当FTP服务器仍在文件上锁定时,文件移动操作将引发异常。当文件仍在上载但尚未完成,但在磁盘上“可见”时,可能会发生这种情况。这种碰撞很少见,但是会发生。

首先检查您的FTP服务器设置和功能,看看它是否可以在上传过程中隐藏不完整的文件。另一种方法是,如果您控制上传文件的系统,则可以使用特殊的“请勿下载”扩展名上传文件,并在上传完成后对其进行重命名(原子操作)。最后,正如其他人指出的那样,您可以简单地捕获此特定异常并延迟重试。

答案 1 :(得分:0)

正如其他人指出的那样,如果进程定期运行,则只需用try / catch块将其包装即可:

try
{
    srcFile.MoveTo(tmpFilename);
}
catch (Excption ex)
{
    // Write log entry if required
    continue;
}

如果这是一个一次性的过程,则需要定期尝试MoveTo,直到文件被释放并可以移动为止。这样的事情可能会起作用:

int maxRetries = 60;
int retries = 0;
bool success = false;
while (retries < maxRetries)
{
    try
    {
        retries++;
        srcFile.MoveTo(tmpFilename);
        success = true;
        break;
    }
    catch (Excption ex)
    {
        // Log the error if required
        Thread.Sleep(1000); // Wait 1 second
    }
}
if (success == fale)
{
    // Log the error
    continue; // Skip the file if its still not released
}

该代码尝试在一分钟内每秒访问一次文件。如果失败,则程序将跳过此文件并继续下一个操作。