我正在编写一个Windows服务来处理由我无法控制的另一个进程创建的文件。这些文件可能非常大(数百兆字节)。
我需要在创建文件后处理然后删除它们。
所有文件都将被写入特定目录(据我所知,只能通过直接文件复制),因此我可以定期迭代该目录中的文件,处理它们然后删除它们。 / p>
我担心的是,如果我的服务在写入大文件期间查询目录会发生什么?该文件是否会显示给我的服务?它会被锁定,以至于我无法获得读取权限吗?我是否需要执行任何特殊操作来检查文件是否已完成复制,还是只需查询File.Exists()
或尝试使用FileAccess.Read
打开它。 Windows如何标记正在复制的文件?
答案 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)
使用临时文件名编写文件,然后重命名该文件。
重命名是一个不正常的过程,因此处理文件的服务应该没问题。只需确保该服务跳过临时文件名。