在软件开发过程中,经常需要监控其他程序的活动进度或状态。本文介绍的工具就是基于这样的需求设计的。它假设被监控的程序会将编号的状态消息写入到一个文本文件中。工具使用FileSystemWatcher
来检测文件的变化,并读取消息在对话框中显示。最初,尝试让主程序一次只写一条消息到消息文本文件中,但很快发现这种方法很脆弱,因为快速操作可能无法快速写入文件。因此,尝试让主程序维护一个包含最后20条消息的列表,并在每次生成新消息时尝试写入文件。如果一些写入失败,也没有问题,因为接下来的写入会包含那些丢失的消息。监控程序每次文件变化时读取文件,并过滤掉过去的信息,然后显示新的信息。报告对话框在一定时间延迟后关闭,或者如果消息文本文件被删除,则关闭。这些细节使得这个工具更有价值。它允许使用任何其他语言编写的程序,可能是不容易支持多线程的程序,并可靠地看到某个活动的进度报告。
编写这个工具是为了帮助编写Autodesk的AutoCAD程序。在Windows XP上显示进度条的工具,在Windows 7上的行为不同,所以必须做一些处理来应对长时间进程的UI“阻塞”。AutoCAD工具是用AutoLisp编写的,特别想要一个外部进程来做报告,所以完全没有阻塞的机会。
要使用状态监视器,将作为外部进程运行StatusByFileWatch.exe
。它接受两个命令行参数,按此顺序:完整的文本文件名和对话框在没有活动时自行关闭的延迟时间(以微秒为单位)。演示程序是用C#编写的,但这里的原则适用于任何语言。在需要监视其消息的任何程序中,设置以下变量:
string _exeLoc = @"C:\+Storage\Programming\DotNet\StatusByFileWatch\bin\Release\StatusByFileWatch.exe";
string _txtFilename = Environment.GetEnvironmentVariable("TEMP") + @"\Logfile for Demo.txt";
List _msgs = new List();
int _bufflen = 20;
然后,在需要监视消息的任何进程中,将:
delete the textfile
clear the message list variable
write a new message to the text file using the writeStatusMsg function
start the StatusByFileWatch.exe with desired arguments
use WriteStatusMsg to add messages as some process proceeds
delete the text file when done displaying the messages (or do nothing and let the dialog close on its own based on the close delay argument)
注意,如果消息列表长度超过,它会自动删除第一条消息。
private void writeStatusMsg(string msg) {
if (_msgs.Count >= _bufflen)
_msgs.RemoveAt(0);
_msgs.Add(_msgIndex.ToString() + ", " + msg);
_msgIndex++;
try {
TextToFile(_txtFilename, _msgs.ToArray());
} catch { }
}
每个语言都有启动外部EXE、写入和删除文本文件的工具,所以这种模式可以被任何语言采用。
一个非常重要的点是,监视器必须以一种不妨碍被监视程序写入文件的方式读取文本文件。这个函数就做得很好:
public static bool TextFiletoList(string fName, out List fileLines) {
fileLines = new List();
if (File.Exists(fName)) {
FileStream fs = new FileStream(fName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (StreamReader sReader = new StreamReader(fs)) {
string text = sReader.ReadLine();
while (text != null) {
fileLines.Add(text);
text = sReader.ReadLine();
}
}
}
if (fileLines.Count > 0) {
return true;
} else {
return false;
}
}
创建FileStream
的那一行至关重要。