I'd like to be notified when a file has been changed in the file system. I have found nothing but a thread that polls the lastModified File property and clearly this solution is not optimal.
-
16Just a note. When we solved this problem before we found that large files tend to come in slowly, and the polling mechanism often discovered a new or changed file before it was fully written. To solve this a 'two bite' solution was adopted. The poller noticed a file had changed, but didn't notify the system of a new/changed file until it looked the same for two polls: i.e. had stabilized. Cured a lot of badfile errors. – Steve Powell Feb 22 '12 at 11:23
-
1As an aside, Tomcat suffers that problem when dropping large WAR files into the webapps folder from remote sources and has done so for a long time. – John Rix Apr 30 '15 at 11:47
-
I am sure there are more elegant ways to do it, but you could save the checksum of the file and then keep comparing it. – magicmn Jan 17 '21 at 00:24
14 Answers
I've written a log file monitor before, and I found that the impact on system performance of polling the attributes of a single file, a few times a second, is actually very small.
Java 7, as part of NIO.2 has added the WatchService API
The WatchService API is designed for applications that need to be notified about file change events.

- 4,485
- 4
- 48
- 56

- 36,219
- 10
- 45
- 60
-
12i see the examples as watching directory, but what about an individual file? – Archimedes Trajano Jul 09 '12 at 13:46
-
@ArchimedesTrajano The API notifies you when a file in a directory has changed. The event that is triggered includes the name of the file that has changed. So you can handle events for a certain file or files and ignore others. – Michael May 06 '14 at 16:29
-
@ArchimedesTrajano https://stackoverflow.com/questions/16251273/can-i-watch-for-single-file-change-with-watchservice-not-the-whole-directory – user1742529 Mar 22 '15 at 07:07
I use the VFS API from Apache Commons, here is an example of how to monitor a file without much impact in performance:

- 1,866
- 21
- 36

- 4,794
- 7
- 31
- 39
There is a lib called jnotify that wraps inotify on linux and has also support for windows. Never used it and I don't know how good it is, but it's worth a try I'd say.

- 12,971
- 3
- 33
- 45
-
1It works perfectly and super simple to use. I've been using inotify for many years. It is fast, stable and reliable – oᴉɹǝɥɔ Jun 11 '13 at 18:31
Since JDK 1.7, the canonical way to have an application be notified of changes to a file is using the WatchService API. The WatchService is event-driven. The official tutorial provides an example:
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;
/**
* Example to watch a directory (or tree) for changes to files.
*/
public class WatchDir {
private final WatchService watcher;
private final Map<WatchKey,Path> keys;
private final boolean recursive;
private boolean trace = false;
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>)event;
}
/**
* Register the given directory with the WatchService
*/
private void register(Path dir) throws IOException {
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
if (trace) {
Path prev = keys.get(key);
if (prev == null) {
System.out.format("register: %s\n", dir);
} else {
if (!dir.equals(prev)) {
System.out.format("update: %s -> %s\n", prev, dir);
}
}
}
keys.put(key, dir);
}
/**
* Register the given directory, and all its sub-directories, with the
* WatchService.
*/
private void registerAll(final Path start) throws IOException {
// register directory and sub-directories
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException
{
register(dir);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Creates a WatchService and registers the given directory
*/
WatchDir(Path dir, boolean recursive) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey,Path>();
this.recursive = recursive;
if (recursive) {
System.out.format("Scanning %s ...\n", dir);
registerAll(dir);
System.out.println("Done.");
} else {
register(dir);
}
// enable trace after initial registration
this.trace = true;
}
/**
* Process all events for keys queued to the watcher
*/
void processEvents() {
for (;;) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
Path dir = keys.get(key);
if (dir == null) {
System.err.println("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
// TBD - provide example of how OVERFLOW event is handled
if (kind == OVERFLOW) {
continue;
}
// Context for directory entry event is the file name of entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
// print out event
System.out.format("%s: %s\n", event.kind().name(), child);
// if directory is created, and watching recursively, then
// register it and its sub-directories
if (recursive && (kind == ENTRY_CREATE)) {
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
registerAll(child);
}
} catch (IOException x) {
// ignore to keep sample readbale
}
}
}
// reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
}
}
static void usage() {
System.err.println("usage: java WatchDir [-r] dir");
System.exit(-1);
}
public static void main(String[] args) throws IOException {
// parse arguments
if (args.length == 0 || args.length > 2)
usage();
boolean recursive = false;
int dirArg = 0;
if (args[0].equals("-r")) {
if (args.length < 2)
usage();
recursive = true;
dirArg++;
}
// register directory and process its events
Path dir = Paths.get(args[dirArg]);
new WatchDir(dir, recursive).processEvents();
}
}
For individual files, various solutions exist, such as:
Note that Apache VFS uses a polling algorithm, although it may offer greater functionality. Also note that the API does not offer a way to determine whether a file has been closed.

- 30,436
- 41
- 178
- 315

- 17,065
- 2
- 26
- 22
-
3That API is overly complex. If forces you to implement/manage a thread with an "endless" loop just to use it. And then you have to watch out for so-called "OVERFLOW" events that mean you missed something, but who knows what. It actually *adds* work on the programmer, for the often overkill benefit of native dir change notifications (if even supported by the filesystem, otherwise it defaults to polling internally anyway). It would have been nice if it followed a simple listener pattern. For example: WatchService.watch(File f, FileListener listener), where f could be a dir or file. Too bad. – Chris Janicki Aug 30 '20 at 20:56
Java commons-io has a FileAlterationObserver. it does polling in combination with a FileAlterationMonitor. Similar to commons VFS. The advantag is that it has much less dependencies.
edit: Less dependencies is not true, they are optional for VFS. But it uses java File instead of the VFS abstraction layer.

- 3,551
- 1
- 28
- 24
I run this snippet of code every time I go to read the properties file, only actually reading the file if it has been modified since the last time I read it. Hope this helps someone.
private long timeStamp;
private File file;
private boolean isFileUpdated( File file ) {
this.file = file;
this.timeStamp = file.lastModified();
if( this.timeStamp != timeStamp ) {
this.timeStamp = timeStamp;
//Yes, file is updated
return true;
}
//No, file is not updated
return false;
}
Similar approach is used in Log4J FileWatchdog
.

- 10,431
- 16
- 76
- 128

- 51
- 1
- 1
"More NIO features" has file watch functionality, with implementation dependent upon the underlying OS. Should be in JDK7.
Update: Was added to Java SE 7. Chris Janicki offers a link to the relevant Java tutorial.

- 145,806
- 30
- 211
- 305
-
Could you be more specific or post a link to documentation? Can't seem to find anything on this ... – Luciano Apr 09 '14 at 07:04
-
It seems to be the package `java.nio.file`. See a [tutorial](https://docs.oracle.com/javase/tutorial/essential/io/notification.html). – David L. Jan 07 '20 at 14:41
-
1https://docs.oracle.com/javase/tutorial/essential/io/notification.html – Chris Janicki Aug 30 '20 at 20:03
You can listen file changes using a FileReader. Plz see the example below
// File content change listener
private String fname;
private Object lck = new Object();
...
public void run()
{
try
{
BufferedReader br = new BufferedReader( new FileReader( fname ) );
String s;
StringBuilder buf = new StringBuilder();
while( true )
{
s = br.readLine();
if( s == null )
{
synchronized( lck )
{
lck.wait( 500 );
}
}
else
{
System.out.println( "s = " + s );
}
}
}
catch( Exception e )
{
e.printStackTrace();
}
}

- 357
- 1
- 2
- 9
If you are willing to part with some money, JNIWrapper is a useful library with a Winpack, you will be able to get file system events on certain files. Unfortunately windows only.
See https://www.teamdev.com/jniwrapper.
Otherwise, resorting to native code is not always a bad thing especially when the best on offer is a polling mechanism as against a native event.
I've noticed that Java file system operations can be slow on some computers and can easily affect the application's performance if not handled well.

- 22,334
- 15
- 80
- 130

- 171
- 7
Spring Integration provides a nice mechanism for watching Directories and files: http://static.springsource.org/spring-integration/reference/htmlsingle/#files. Pretty sure it's cross platform (I've used it on mac, linux, and windows).

- 12,916
- 10
- 62
- 72
You may also consider the Apache Commons JCI (Java Compiler Interface). Although this API seems to be focused on dynamic compilation of classes, it also includes classes in its API that monitors file changes.

- 4,771
- 9
- 32
- 35
Polling the last modified file property is a simple yet effective solution though. Just define a class extending my FileChangedWatcher
and implement the onModified()
method:
import java.io.File;
public abstract class FileChangedWatcher
{
private File file;
public FileChangedWatcher(String filePath)
{
file = new File(filePath);
}
public void watch() throws InterruptedException
{
long currentModifiedDate = file.lastModified();
while (true)
{
long newModifiedDate = file.lastModified();
if (newModifiedDate != currentModifiedDate)
{
currentModifiedDate = newModifiedDate;
onModified();
}
Thread.sleep(100);
}
}
public String getFilePath()
{
return file.getAbsolutePath();
}
protected abstract void onModified();
}

- 17,329
- 10
- 113
- 185
Similar to the other answers, here's how I did it using File, Timer, and TimerTask to let this run as a background thread polling at set intervals.
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
public class FileModifiedWatcher
{
private static File file;
private static int pollingInterval;
private static Timer fileWatcher;
private static long lastReadTimeStamp = 0L;
public static boolean init(String _file, int _pollingInterval)
{
file = new File(_file);
pollingInterval = _pollingInterval; // In seconds
watchFile();
return true;
}
private static void watchFile()
{
if ( null == fileWatcher )
{
System.out.println("START");
fileWatcher = new Timer();
fileWatcher.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
if ( file.lastModified() > lastReadTimeStamp )
{
System.out.println("File Modified");
}
lastReadTimeStamp = System.currentTimeMillis();
}
}, 0, 1000 * pollingInterval);
}
}
}

- 43
- 3
There is a commercial cross-desktop library for files and folders watching called JxFileWatcher. It can be downloaded from here: http://www.teamdev.com/jxfilewatcher/
Also you can see it in action online: http://www.teamdev.com/jxfilewatcher/onlinedemo/

- 67,400
- 29
- 193
- 254