Search code examples
javafile-iopolling

Java: how to poll a small file over and over to see if it changed? (watching can't work)


What is the least-overhead way in Java 8+ to poll/read a small plain ASCII file to check if it changed?

I have a device that creates a fake filesystem (ev3dev) that provides small read-only files with status updates. (eg. a lego motor's position in a position file with a single Int, or the motor's status in a status file with a single String, both served up as a plain ASCII file)

Things that didn't work:

  1. Java's Watcher service doesn't work, I think because the OS is never notified that the file changed. (the modified time stays the same, and the file size is constant.) I tried -- it never triggers. Oh well!
  2. Setting a mark() and reset() to read the file over and over without creating a new Reader doesn't seem to work on a BufferedReader, are there ways to make it work?

I think I have to poll: quickly read the file over and over (and over. and over!)

  • Can I use a memory-mapped file (will it pick up the changes?)
  • Some way to keep everything open and do a mark/reset or similar to pick up changes?
  • Or just bite the bullet and call Files.readAllBytes in its own thread with a 1ms delay between loops?

Solution

  • You can use the RandomAccessFile class for your code.

    My code :

    import java.io.*; //Importing RandomAccessFile Class
    import java.util.*; // Thread.sleep(milliseconds)
    public class Main {
        public static void main(String[] args) throws Exception {
            Scanner scan = new Scanner(System.in);
            /*Just To add functionality I have also specified the time at which the file is modified*/
            System.out.println("Input File Path : ");
            String file_path = scan.nextLine();
            RandomAccessFile f = new RandomAccessFile(file_path,"r");
            int character;
            String Intitalval="";
            while ((character = f.read()) != -1) {
                Intitalval+=(char)character;
            }
            f.seek(0);
            boolean nochange = true;
            while (nochange) {
                String ToCompare="";
                while ((character = f.read()) != -1) {
                    ToCompare+=(char)character;
                }
    
                if (!ToCompare.equals(Intitalval)) {
                    nochange = false;
                    System.out.println("The file has been modified at " + java.time.LocalTime.now());
                }
                Thread.sleep(1);
                f.seek(0);
            }
            f.close();
        }
    }
    

    As you said you want a delay of 1 millisecond I have used java Thread.sleep(int milliseconds) method.

    The program will also display the time at which the file is modified (not accurate (+- milliseconds)).

    Output :

    Output/results