2016-06-16 4 views
0

У меня есть консольное приложение, которое использует fileSystemWatcher для отслеживания сопоставленного сетевого пути для новых файлов. Когда файлы появляются, они переименовываются на основе содержимого файлов. Я хочу, чтобы это продолжалось 24/7. На какое-то время это работает нормально, но я обнаружил, что через некоторое время консоль «приостанавливается» и, кажется, ждет ввода. Если я нажму на возврат в консоли, приложение, похоже, догонит все события, которые, похоже, находятся в ожидании ожидающего ввода какого-либо типа. Я никогда не могу воспроизвести эту проблему, чтобы поймать ее в коде, где она приостанавливается или почему.Консольное приложение «приостановка» C#

Я предположил, что это связано с тем, что наблюдатель файловой системы потерял способность отслеживать сетевой путь из-за внешних факторов (перезагрузка сервера, проблемы с сетью и т. Д.), Поэтому я воссоздал наблюдателя файловой системы за 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); 

} 
+1

Возможно ли, что вы выбрали текст с помощью мыши в консоли? – recursive

+3

У вас есть бесконечно рекурсивная программа с 'getInput()'. Если вам не повезет, и компилятор не выполнил рекурсию хвоста, вы, в конце концов, получите StackOverflow. Просто используйте вместо этого цикл while (true). –

+0

Нет. Это будет происходить, иногда в течение дня или около того, до того, как это произойдет, и никто не сможет этого сделать. – rune711

ответ

0

Чтобы избавиться от исключения StackOverflow (что может вызвать путем вызова GetInput() в GetInput()) (как сказал Скотт) Используйте в то время как цикл вместо рекурсивного вызова метода.

Это не должно быть необходимо для воссоздания FileSystemWatcher. Вероятно, вы получаете исключение, пытаясь прочитать файл, потому что он еще не написан.

Пример использовать время цикла вместо рекурсивного метода вызова:

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 исключение, ocurs, вы никогда не повторить его. Вы можете добавить имя файла в List<string> и создать таймер, который пытается проанализировать файл, если удастся, вы можете удалить его из списка. Это можно сделать с помощью команды runAll. вместо прямого анализа файлов все файлы могут быть добавлены в список.

+0

Извините, но я не думаю, что это ответ на вопрос, хотя @Scott, безусловно, верен в своем совете о времени (правда) , Из-за того, как срабатывает событие FileSystemWatcher, даже если файл не был заполнен, я включил логику в parseTheFile(), которая выполняет некоторые проверки блокировки файлов и обработку ошибок. Однако, даже если в событии была выброшена ошибка, я не думаю, что это объяснит поведение, которое я вижу. – rune711

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() с события. Это событие не может завершиться до тех пор, пока я не вернусь назад, и, кроме того, я забыл отказаться от подписки на это событие при воссоздании файла SystemSystemWatcher, как отмечал @Jeroen. Это объясняет, почему, когда я попадаю в ответ, это каскадный эффект от всех других событий?Как-то консоль «приостанавливает» ожидание всех этих «ReadLines» в этих событиях? Я исправил это и провел его прошлой ночью, и сегодня все хорошо, поэтому я отправлю сообщение снова, если снова увижу проблему, но я уверен, что это все.

Смежные вопросы