3

Process在我们的 C# WinForms 应用程序中,我们生成 PDF 文件并通过该类启动 Adob​​e Reader(或任何默认系统 .pdf 处理程序) 。由于我们的 PDF 文件可能很大(大约 200K),我们处理该Exited事件然后清理临时文件。

当文件被打开然后再次关闭时,系统会按要求工作。但是,当打开第二个文件时(在关闭 Adob​​e Reader 之前),第二个进程会立即退出(因为 Reader 现在正在使用它的 MDI 功能)并且在我们的Exited处理程序中,我们的 File.Delete 调用应该会失败,因为它已被现在加入的 Adob​​e 进程锁定。然而,在阅读器中,我们得到:

打开此文档时出错。找不到该文件。

不寻常的是,如果我在文件删除之前放置一个调试器断点并允许它尝试(并失败)删除,那么系统会按预期运行!

我很肯定该文件存在,并且相当肯定该文件的所有句柄/文件流在开始该过程之前都已关闭。

我们使用以下代码启动:

// Open the file for viewing/printing (if the default program supports it) 
var pdfProcess = new Process();
pdfProcess.StartInfo.FileName = tempFileName;
if (pdfProcess.StartInfo.Verbs.Contains("open", StringComparer.InvariantCultureIgnoreCase))
{
    var verb = pdfProcess.StartInfo.Verbs.First(v => v.Equals("open", StringComparison.InvariantCultureIgnoreCase));
    pdfProcess.StartInfo.Verb = verb;
}
pdfProcess.StartInfo.Arguments = "/N"; // Specifies a new window will be used! (But not definitely...)
pdfProcess.SynchronizingObject = this;
pdfProcess.EnableRaisingEvents = true;
pdfProcess.Exited += new EventHandler(pdfProcess_Exited);

_pdfProcessDictionary.Add(pdfProcess, tempFileName);

pdfProcess.Start();

注意:我们使用_pdfProcessDictionary来存储对 Process 对象的引用,以便它们保持在范围内,以便可以成功引发 Exited 事件。

我们的清理/退出事件是:

void pdfProcess_Exited(object sender, EventArgs e)
{
    Debug.Assert(!InvokeRequired);
    var p = sender as Process;
    try
    {
        if (_pdfProcessDictionary.ContainsKey(p))
        {
            var tempFileName = _pdfProcessDictionary[p];
            if (File.Exists(tempFileName)) // How else can I check if I can delete it!!??
            {
                // NOTE: Will fail if the Adobe Reader application instance has been re-used!
                File.Delete(tempFileName);
                _pdfProcessDictionary.Remove(p);
            }

            CleanOtherFiles(); // This function will clean up files for any other previously exited processes in our dictionary
        }
    }
    catch (IOException ex)
    {
        // Just swallow it up, we will deal with trying to delete it at another point
    }
}

可能的解决方案:

  • 检测文件是否还在另一个进程中打开
  • 检测到第二个进程还没有真正完全退出,而是在第一个进程中打开了文件
4

2 回答 2

3

几天前我刚刚处理了这个问题。

当没有实例打开时,文档直接在新实例中打开。

当有一个实例已经打开时,我相信该实例会产生一个您实际上并没有处理的新实例。发生的情况是控制权立即返回到您的函数,然后在新实例有机会读取文件之前删除文件 - 因此它似乎不存在。

我通过不立即删除文件来“解决”这个问题,而是跟踪列表中的路径,然后在程序退出时对所有路径进行核对(将每个删除都包装在 try/catch 中,并使用空的 catch 块,以防文件期间消失了)。

于 2010-12-21T05:14:23.117 回答
1

我建议以下方法:

  1. 在用户的临时目录 ( Path.GetTempPath ) 中创建文件。您可以在其下创建一些子文件夹。
  2. 仅在进程的最后一个实例退出时尝试删除文件(即,您需要计算已启动的进程数,退出时减少计数,当它变为零时,尝试删除到目前为止打开的(所有)文件)
  3. 尝试在启动和结束应用程序时清理创建的子文件夹(在 temp 目录下)。您甚至可以尝试使用计时器进行定期清理。
于 2010-12-21T05:06:12.563 回答