1

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?
Benjamin H
  • 5,164
  • 6
  • 34
  • 42
  • regarding your first point, as per my view OS will only be notified about the folder in which file has changed and triggered event will contain the name of the file changed. see if this link helps : https://stackoverflow.com/questions/494869/file-changed-listener-in-java – adhikari Jul 28 '20 at 05:40
  • How quickly do you need to be notified? Would polling it once every five seconds be fast enough? – NomadMaker Jul 28 '20 at 23:24

1 Answers1

1

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

halfer
  • 19,824
  • 17
  • 99
  • 186
Shiv Patel
  • 114
  • 7
  • 1
    Worked great, thank you! https://github.com/salamanders/utils/blob/e8c085cc6bcd50edeef0a8b75695cb99f09b02ab/src/main/kotlin/info/benjaminhill/utils/Flows.kt#L55 – Benjamin H Jul 29 '20 at 17:44