我有一个控制台应用程序,它使用fileSystemWatcher来监视新文件的映射网络路径。当文件出现时,它们会根据文件的内容重命名。我希望这个全天候运行。一段时间它工作正常,但我发现一段时间后控制台“暂停”,似乎在等待输入。如果我在控制台中点击返回,应用程序似乎赶上所有似乎已经处于等待某种类型输入的“待处理”事件。我似乎永远不会重现这个问题,以便在代码中捕获它,因为它暂停或为什么。
我认为这与文件系统观察者因外部因素(服务器重启,网络问题等)而无法监控网络路径有关,所以我重新创建文件系统观察者30分钟。我很确定实际上与现在的情况无关。
基本上我所看到的是控制台很乐意在找到的新文件上打印出更新等等但是它只会停止(程序操作,而不仅仅是输出)并且永远不会继续,直到我将焦点放在控制台应用程序上并点击一些键然后所有挂起的事件(如计时器过去和文件系统观察者重新创建)都发生了。
问题是:为什么会发生这种情况,我该如何预防呢?
该计划的细节如下:
static void Main(string[] args)
{
RefreshTimer = new Timer(1800000); //30 minutes
RefreshTimer.Elapsed += RefreshTimer_Elapsed;
RefreshTimer.Enabled = true;
writeHelp();
reCreateWatcher();
getInput();
}
private static void writeHelp()
{
Console.WriteLine("HELP:");
Console.WriteLine(@"");
Console.WriteLine("RENAMES FILES THAT ARE PLACED INTO THE WORKING FOLDER.");
Console.WriteLine("*************_Commands:_************");
Console.WriteLine("'runAll' = will run the program on all files curently existing in the folder. Note that if a file has already been renamed the program SHOULD attempt the rename, find the file has already been renamed, and move to the next file.");
Console.WriteLine("'quit' = exits program");
Console.WriteLine("'help' = shows this spiffy information.");
Console.WriteLine("[end]");
Console.WriteLine("");
}
private static void getInput()
{
Console.Write("Cmd ->");
string k = Console.ReadLine();
switch (k)
{
case "help":
writeHelp();
break;
case "runAll":
string[] allFiles = System.IO.Directory.GetFiles(PATH_TO_FILES);
foreach (string curr in allFiles)
{
parseTheFile(curr);
}
break;
case "quit":
return;
default:
Console.WriteLine("Huh? Unknown command!");
break;
}
getInput();
}
private static void reCreateWatcher()
{
Console.WriteLine("re-starting watcher...");
Console.WriteLine("Starting Monitor of: " + PATH_TO_FILES);
if (TheWatcher != null)
{
TheWatcher.Dispose();
}
deleteOldFiles();
try
{
TheWatcher = new FileSystemWatcher(PATH_TO_FILES, "*.pdf");
}
catch (Exception ex)
{
Console.WriteLine("AN ERROR OCCURED WHEN TRYING TO SET UP THE FILE SYSTEM WATCHER ON, '" + PATH_TO_FILES + "'. THE ERROR WAS: " + ex.Message);
Console.WriteLine("Hit any key to exit.");
Console.ReadKey();
Environment.Exit(0);
}
TheWatcher.NotifyFilter = NotifyFilters.LastWrite;
TheWatcher.Changed += theWatcher_Changed;
TheWatcher.EnableRaisingEvents = true;
}
static void theWatcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("New file found: " + e.Name);
parseTheFile(e.FullPath);
}
答案 0 :(得分:0)
要摆脱Stackoverflow异常(这可能是通过调用GetInput()
中的GetInput()
)(如Scott所说)使用while循环而不是递归方法呼叫。
不需要重新创建FileSystemWatcher。尝试读取文件时可能会出现异常,因为尚未完成写入。
使用while循环而不是递归方法调用的示例:
class Program
{
private static readonly string PATH_TO_FILES = @"d:\temp";
static void Main(string[] args)
{
using (var watcher = new FileSystemWatcher(PATH_TO_FILES, "*.pdf"))
{
watcher.Changed += Watcher_Changed;
WriteHelp();
while (true)
{
Console.Write("Cmd ->");
string k = Console.ReadLine();
switch (k)
{
case "help":
WriteHelp();
break;
case "runAll":
string[] allFiles = System.IO.Directory.GetFiles(PATH_TO_FILES);
foreach (string curr in allFiles)
{
parseTheFile(curr);
}
break;
case "quit":
return;
default:
Console.WriteLine("Huh? Unknown command!");
break;
}
}
}
}
private static void WriteHelp()
{
Console.WriteLine("HELP:");
Console.WriteLine(@"");
Console.WriteLine("RENAMES FILES THAT ARE PLACED INTO THE WORKING FOLDER.");
Console.WriteLine("*************_Commands:_************");
Console.WriteLine("'runAll' = will run the program on all files curently existing in the folder. Note that if a file has already been renamed the program SHOULD attempt the rename, find the file has already been renamed, and move to the next file.");
Console.WriteLine("'quit' = exits program");
Console.WriteLine("'help' = shows this spiffy information.");
Console.WriteLine("[end]");
Console.WriteLine("");
}
private static void Watcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
Console.WriteLine("New file found: " + e.Name);
parseTheFile(e.FullPath);
}
catch(Exception exception)
{
Console.WriteLine("Exception: " + exception.Message);
}
}
private static void parseTheFile(string fullPath)
{
throw new NotImplementedException();
}
}
问题是,当在FileSystemWatcher事件中发生异常时,您永远不会重试它。您可以将文件名添加到List<string>
并创建一个尝试解析文件的计时器,如果成功,您可以将其从列表中删除。这可以使用命令runAll
完成。所有文件都可以添加到列表中,而不是直接解析文件。
答案 1 :(得分:0)
啊!我想我看到了什么发生了,我很遗憾整个节目没有在这里发布,因为其他人肯定会看到这一点。正如@Scott Chamberlain所说,getInput()方法中存在递归。但是我也注意到在parseTheFile()中还包括对getInput()的调用,具体取决于以下情况:
static private void parseTheFile(string thePath)
{
Console.WriteLine("Attempting to parse " + System.IO.Path.GetFileName(thePath));
string fileText;
try
{
fileText = GetTextFromPdf(thePath);
}
catch (Exception ex)
{
Console.WriteLine("An error was encountered when trying to parse the file. " + ex.Message);
getInput(); // <---- WHOOPS!
return;
}...
我显然对事件,静态方法和控制台应用程序有一些了解。基本上我看到的是程序启动,转到getInput(),它在字符串k = Console.ReadLine();等待。然而,事件然后触发一个新文件,然后可能从事件中再次调用getInput()。直到我点击返回时,该事件才能完成,另外,在重新创建fileSystemWatcher时,我忽略了取消订阅该事件,如@Jeroen所述。这就解释了为什么当我点击返回时,所有其他事件都会产生这种级联效应?某种程度上,控制台正在“暂停”等待这些事件中的所有这些“ReadLines”?我修好了,昨天晚上运行了,今天早上一切都还好,所以如果我再次看到问题,我会再次发帖,但我很确定这就是它。