5

How might I watch for a specific file to change in a directory using Mathematica/.NET code?

The following works in .NET but fires twice when you change the file.

using System;

public class Watcher
{
    public static int exit=1;
    static DateTime lastRead = DateTime.MinValue;
    public static void Main()
    {
        System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher();
        watcher.Path = "C:\\Users\\a\\Desktop";
        watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite;
        watcher.Filter = "test.txt";
        watcher.Changed += new System.IO.FileSystemEventHandler(OnChanged);
        watcher.EnableRaisingEvents = true;
        while (exit != 0) ;
    }
    private static void OnChanged(object source, System.IO.FileSystemEventArgs e)
    {
        DateTime lastWriteTime = System.IO.File.GetLastWriteTime(e.FullPath);
        if (lastWriteTime != lastRead)
        {
            Console.Write(
              System.IO.File.ReadAllText(e.FullPath)
            );
            exit = 0;
            lastRead = lastWriteTime;
        }
    }
}

to compile

C:\Windows\Microsoft.Net\Framework\v4.0.30319\csc.exe test.cs

Here is the starting code for Mathematica.

Needs["NETLink`"];
InstallNET[];
myHandler[source_, e_] := Print["File editted"];
w = NETNew["System.IO.FileSystemWatcher"];
LoadNETType["System.IO.NotifyFilters"];
w@Path = "C:\\Users\\a\\Desktop";
w@NotifyFilter = NotifyFilters`LastWrite;
w@Filter = "*.txt";
e = AddEventHandler[w@Changed, myHandler];
w@EnableRaisingEvents = True;
William
  • 7,595
  • 2
  • 22
  • 70

1 Answers1

4

There are 2 techniques. Because of the following bug here(or feature).

Needs["NETLink`"];
InstallNET[];

ShowNETConsole["stdout"];
LoadNETType["System.Console"];
Console`Out@WriteLine["Hello from .NET"];

WatchFile[file_String, fun_] := 
  Module[{time, time2, w, e},
   w = NETNew["System.IO.FileSystemWatcher"];
   LoadNETType["System.IO.NotifyFilters"];
   LoadNETType["System.IO.File"];
   w@Path = FileNameJoin@Drop[FileNameSplit[file], -1];
   w@NotifyFilter = NotifyFilters`LastWrite;
   w@Filter = Last@FileNameSplit[file];
   e = AddEventHandler[w@Changed, myHandler];
   time = 0;
   myHandler[source_, e_] := (
     time2 = File`GetLastWriteTime[file]@ToBinary[];
     If[time == time2,
      Null;,
      fun[source,e];];
     time = time2;
     );
   w@EnableRaisingEvents = True;
   Return[{w, e}];];
WatchFile["C:\\cygwin64\\home\\a\\test.txt", 
 Function[{w, e}, Console`Out@WriteLine[e@FullPath]]]

Along with the following technique with watching for content to change in the myHandler.

content = Import[file, "Plaintext"];
myHandler[source_, e_] := (
   content2 = Import[file, "Plaintext"];
   If[content != content2,
    fun[source,e];
    ];
   content = content2;
   );
William
  • 7,595
  • 2
  • 22
  • 70