【问题标题】:Can I tell if another process is in the process of creating a file?我可以判断是否有另一个进程正在创建文件吗?
【发布时间】:2011-03-07 10:15:11
【问题描述】:

我正在编写一个 Windows 服务来处理由另一个我无法控制的进程创建的文件。这些文件可能非常大(数百兆字节)。

我需要在创建文件后处理并删除它们。

所有文件都将写入特定目录(据我所知,仅通过直接文件副本),因此我可以定期迭代该目录中的文件,处理它们然后删除它们。

我担心的是,如果我的服务在写入大文件期间查询目录会发生什么?该文件会显示给我的服务吗?它会被锁定以使我无法获得读取权限吗?我是否需要做任何特别的事情来检查文件是否已完成复制,或者我可以只查询File.Exists() 或尝试使用FileAccess.Read 打开它。 Windows 如何标记正在复制的文件?

【问题讨论】:

    标签: c# windows file locking


    【解决方案1】:

    如果这是普通的 win32,您将尝试使用CreateFile() 和拒绝其他人写访问的共享模式打开文件。如果其他程序仍在写入文件,那将不得不失败,因为当文件已经以写入访问权限打开时,您无法拒绝写入访问。如果成功了,就知道其他进程已经结束了。

    例如,在.net 中,您可以使用接收FileShare 参数的构造函数之一创建FileStream。这最终将映射到底层的CreateFile() API。

    【讨论】:

      【解决方案2】:

      AFAIK 文件中没有特殊标记表明它正在被复制,除了它会有一个写锁。在这种情况下,标准做法是尝试使用写锁(例如 FileShare.Read)自己打开文件,并捕获由于文件已被锁定而发生的任何 IOException;在这种情况下,请在重试打开文件之前暂停一下 (Thread.Sleep)。您可能想要限制重试次数(以防止在现有文件锁永远不会释放的情况下出现无限循环)。

      您说您要处理文件然后删除它们?为了避免在处理/删除文件时与另一个进程/线程写入同一文件的竞争,您应该将处理/删除视为原子操作,例如,如下所示:

      string sourcePath = @"C:\temp1\temp.txt";
      string targetPath = @"C:\temp2\temp.txt";
      int attempt = 0;
      const int maxAttempts = 3;
      bool moved = false;
      do
      {
          try
          {
              File.Move(sourcePath, targetPath);
              moved = true;
          }
          catch (IOException)
          {
              if (attempt < maxAttempts)
              {
                  System.Threading.Thread.Sleep(1000);
                  attempt++;
              }
          }
      } while (!moved && attempt < maxAttempts);
      
      if (moved)
      {
           ProcessFile(targetPath);
           File.Delete(targetPath);
      }
      else
      {
          throw new InvalidOperationException("Unable to process '" + sourcePath + "'.");
      }
      

      编辑:我看到你说文件可能非常大,所以你不应该使用 File.ReadAllText。您可以尝试将文件移动到另一个目录 - 这将引发异常,因为文件仍被其他进程锁定。仅当您成功移动文件时才处理该文件。这还具有从输入目录中删除文件的好处。

      【讨论】:

      • 我认为FileAccess.Write 不会导致文件被锁定。控制锁定的是FileShare
      【解决方案3】:

      用临时文件名写入文件,然后重命名文件。

      重命名是一个原子过程,因此您处理文件的服务应该没问题。只需确保服务跳过临时文件名即可。

      【讨论】:

      • 这是 Windows 所做的,还是您建议我应该做的?我无法控制写入过程。
      • "用临时文件名写入文件,然后重命名文件" windows 是否保证这样有效?你有任何官方文件说明这一点吗?在 Linux 上,重命名可以在写入完成之前发生。
      • 我会这样实现,但是你当然需要访问写入过程...
      • 重命名过程的原子性:stackoverflow.com/questions/167414/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多