我可以判断另一个进程是否正在创建文件吗?

时间:2011-03-07 10:15:12

标签: c# windows file locking

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

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

所有文件都将被写入特定目录(据我所知,只能通过直接文件复制),因此我可以定期迭代该目录中的文件,处理它们然后删除它们。 / p>

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

3 个答案:

答案 0 :(得分:2)

如果这是普通的win32,你会尝试使用CreateFile()打开文件,以及拒绝对其他人进行写访问的共享模式。如果其他程序仍在写文件,则必须失败,因为当文件已经通过写访问打开时,您无法拒绝写访问。如果成功,您就知道其他过程已经完成。

在.net中,您可以使用其中一个接收FileStream参数的构造函数创建FileShare。这最终将映射到基础CreateFile() API。

答案 1 :(得分:1)

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。您可以尝试将文件移动到另一个目录 - 这将引发异常,因为该文件仍被其他进程锁定。如果成功移动文件,则只处理该文件。这也有从输入目录中删除文件的好处。

答案 2 :(得分:0)

使用临时文件名编写文件,然后重命名该文件。

重命名是一个不正常的过程,因此处理文件的服务应该没问题。只需确保该服务跳过临时文件名。