The CLR offers with System.IO.FileSystemWatcher a very simple to use class which can be used with X++ in order to identify new created, renamed, deleted and changed (The change of a file or folder. The types of changes include: changes to size, attributes, security settings, last write, and last access time) files in directories and even in the containing subdirectories. Unfortunately X++ does not support the CLR-events, so that the code in X++ will be a little bit more complicated as this would be the case with C#.

The following code shows you how you can use this class with X++:

   1:  public static Container SetStaticFileWatcher()
   2:  {
   3:  System.IO.FileSystemWatcher fw = new System.IO.FileSystemWatcher();
   4:  System.IO.WatcherChangeTypes watcherChangeType;
   5:  System.IO.WaitForChangedResult res;
   6:  Container cont;
   7:  str fileName;
   8:  str oldFileName;
   9:  str changeType;
  10:  ;
  11:   
  12:  //TODO: You can point to the directory you want to observe
  13:  fw.set_Path("c:\\temp");
  14:  //TODO: You can choose if you want to include subdirectories
  15:  fw.set_IncludeSubdirectories(true);
  16:  //TODO: You can define her the name-pattern
  17:  fw.set_Filter("*.txt");
  18:  //TODO: You can choose the type of action you want to observe. Have a look at MSDN…
  19:  watcherChangeType = ClrInterop::parseClrEnum('System.IO.WatcherChangeTypes', 'All');
  20:  res = fw.WaitForChanged(watcherChangeType);
  21:   
  22:  fileName = res.get_Name();
  23:   
  24:  //ChangeTypeName can be: Created, Deleted, Renamed and Changed
  25:  changeType = System.Enum::GetName(watcherChangeType.GetType(), res.get_ChangeType());
  26:   
  27:  //OldName must never be null. You'll receive a X++ error
  28:  if (changeType == 'Renamed')
  29:      oldFileName = res.get_OldName();
  30:   
  31:  cont += fileName;
  32:  cont += changeType;
  33:  cont += oldFileName;
  34:   
  35:  fw.Dispose();
  36:   
  37:  return cont;
  38:  }

And the following job helps you to execute this method:

   1:  static void FileWatcher(Args _args)
   2:  {
   3:  A1FileWatcher fileWatcher = new A1FileWatcher();
   4:  Container cont;
   5:  str fileName;
   6:  str oldFileName;
   7:  str changeType;
   8:  ;
   9:   
  10:  cont = A1FileWatcher::SetFileWatcher();
  11:   
  12:  fileName = conpeek(cont, 1);
  13:  oldFileName = conpeek(cont, 3);
  14:  changeType = conpeek(cont, 2);
  15:  }

The only problem you might face in some scenarios is the fact that the method WaitForChanged in line 20 is executed in the same thread with the rest of your code. This means that the job will wait until something happens (created, deleted, …). In order to prevent this, you need to run this method in a separate thread which I show in the following code  example:

   1:  private static container SetFileWatcher(Thread thread)
   2:  {
   3:  System.IO.FileSystemWatcher fileSystemWatcher;
   4:  System.IO.WatcherChangeTypes watcherChangeType;
   5:  System.IO.WaitForChangedResult res;
   6:  str fileName, oldFileName, changeType;
   7:  str searchPattern, searchPath, searchType;
   8:  Container cont
   9:  ;
  10:   
  11:      fileSystemWatcher = new System.IO.FileSystemWatcher();
  12:      cont =  thread.getInputParm();
  13:      searchPath = conpeek(cont, 1);
  14:      searchPattern = conpeek(cont, 2);
  15:      searchType = conpeek(cont, 3);
  16:   
  17:      System.Diagnostics.EventLog::WriteEntry(searchPath,searchPath);
  18:      fileSystemWatcher.set_Path(searchPath);
  19:      fileSystemWatcher.set_IncludeSubdirectories(true);
  20:      fileSystemWatcher.set_Filter(searchPattern);
  21:      watcherChangeType = ClrInterop::parseClrEnum('System.IO.WatcherChangeTypes', searchType);
  22:   
  23:      //Waiting for the action
  24:      res = fileSystemWatcher.WaitForChanged(watcherChangeType);
  25:      //fileSystemWatcher.Dispose();
  26:   
  27:      fileName = res.get_Name();
  28:      //ChangeTypeName can be: Created, Deleted, Renamed and Deleted
  29:      changeType = System.Enum::GetName(watcherChangeType.GetType(), res.get_ChangeType());
  30:   
  31:   
  32:      //OldName must never be null. You'll receive a X++ error
  33:      if (changeType == 'Renamed')
  34:          oldFileName = res.get_OldName();
  35:   
  36:      //TODO: add here your code
  37:      System.Diagnostics.EventLog::WriteEntry("Hello World","something to do");
  38:   
  39:      //notifies the waiting thread
  40:      thread.notify();
  41:   
  42:      return cont;
  43:  }

And here’s the code that creates the thread and executes the static method above:

   1:  static void main(Args _args)
   2:  {
   3:  Thread fileWatcherThread;
   4:  Container cont;
   5:  Container ouputCont;
   6:  ;
   7:   
   8:      fileWatcherThread = new Thread();
   9:      cont += "c:\\temp";
  10:      cont += "*.txt";
  11:      cont += "All";
  12:      if (fileWatcherThread)
  13:      {
  14:          fileWatcherThread.removeOnComplete(true);
  15:          fileWatcherThread.setInputParm(cont);
  16:          fileWatcherThread.run(classnum(A0FileWatcher), identifierstr(SetFileWatcher));
  17:          fileWatcherThread.setOutputParm(ouputCont);
  18:          //TODO: you can now here work with the retuned values in the container
  19:      }
  20:  }