起初我以为我面临着一个非常简单的任务。但是现在我意识到它不像我想象的那样工作,所以现在我希望你们能帮助我,因为我现在几乎陷入困境。
我的场景是这样的(在 Windows 2008 R2 服务器上):
- 一个文件每天上传 3 次到 FTP 目录。文件名始终相同,这意味着现有文件每次都会被覆盖。
- 我编写了一个简单的 C# 服务,它正在监视 FTP 上传目录,为此我使用 FileSystemWatcher 类。
- 文件的上传需要几分钟,所以一旦文件观察器注册更改,我会定期尝试打开文件,查看文件是否仍在上传(或锁定)
- 一旦文件不再被锁定,我会尝试将文件移动到我的 IIS 虚拟目录中。我必须先删除旧文件,然后将新文件移过来。这就是我的问题开始的地方。该文件似乎总是被 IIS(w3wp.exe 进程)锁定。
经过一番研究,我发现我必须终止锁定文件的进程(在这种情况下为 w3wp.exe)。为此,我创建了一个新的应用程序池并将虚拟目录转换为应用程序。现在我的目录在一个单独的 w3wp.exe 进程下运行,据推测我可以安全地杀死并将新文件移到那里。
现在我只需要找到正确的 w3wp.exe 进程(总共运行 3 个 w3wp.exe 进程,每个进程都在一个单独的应用程序池下运行),它锁定了我的目标文件。但这似乎是 C# 中几乎不可能完成的任务。我在这里发现了很多关于“查找锁定特定文件的过程”的问题,但没有一个答案对我有帮助。例如,进程资源管理器准确地告诉我哪个进程正在锁定我的文件。
接下来我不明白的是,我可以毫无问题地通过 Windows 资源管理器删除目标文件。只是我的 C# 应用程序收到“文件正在被另一个进程使用”错误。我想知道这里有什么区别......
以下是关于锁定文件和 C# 的最值得注意的问题:
^^ 此处的示例代码确实有效,但这会输出每个活动进程的打开句柄 ID。我只是不知道如何搜索特定的文件名,或者至少将句柄 ID 解析为文件名。这个 WinAPI 的东西超出了我的想象。
^^ 这里的示例代码正是我所需要的,但不幸的是我无法让它工作。它总是抛出一个我无法弄清楚的“AccessViolationException”,因为示例代码广泛使用了 WinAPI 调用。
简单的任务,做不到?我很感激任何帮助。
编辑 这里是我的服务器代码的一些相关部分:
检测文件是否被锁定的辅助函数:
private bool FileReadable(string file, int timeOutSeconds)
{
DateTime timeOut = DateTime.Now.AddSeconds(timeOutSeconds);
while (DateTime.Now < timeOut)
{
try
{
if (File.Exists(file))
{
using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None))
{
return true;
}
}
return false;
}
catch (Exception)
{
Thread.Sleep(500);
}
}
m_log.LogLogic(0, "FileReadable", "Timeout after [{0}] seconds trying to open the file {1}", timeOutSeconds, file);
return false;
}
这是我的 FileSystemWatcher 事件中的代码,它正在监视 FTP 上传目录。filepath是新上传的文件,targetfilepath是我的IIS目录下的目标文件。
// here I'm waiting for the newly uploaded file to be ready
if (FileReadable(filepath, FWConfig.TimeOut))
{
// move uploaded file to IIS virtual directory
string targetfilepath = Path.Combine(FWConfig.TargetPath, FWConfig.TargetFileName);
if(File.Exists(targetfilepath))
{
m_log.LogLogic(4, "ProcessFile", "Trying to delete old file first: [{0}]", targetfilepath);
// targetfilepath is the full path to my file in my IIS directory
// always fails because file is always locked my w3wp.exe :-(
if(FileReadable(targetfilepath, FWConfig.TimeOut))
File.Delete(targetfilepath);
}
File.Move(filepath, targetfilepath);
}
EDIT2: 在客户端下载文件时终止 w3wp.exe 进程对我们来说没有问题。我只是很难找到锁定文件的正确 w3wp.exe 进程。
此外,我的客户端应用程序正在客户端上下载文件,它正在检查 HTTP HEAD 的 Last-Modified 日期。客户每 10 分钟检查一次日期。因此,文件可能被 IIS 锁定,因为有客户端不断检查文件的 HTTP HEAD。尽管如此,我不明白为什么我可以通过 Windows 资源管理器手动删除/重命名/移动文件而没有任何问题。为什么这行得通,为什么我的应用程序会出现“被另一个进程锁定”异常?