Note how to use WatchService
to monitor folder and file changes in Java.
OS Window 10
Java
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
Hello World
package sample.watch;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.Watchable;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.WatchEvent.*;
public class Main {
public static void main(String[] args) {
WatchService watcher;
try {
watcher = FileSystems.getDefault().newWatchService();
Watchable path = Paths.get("./build");
path.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (true) {
WatchKey watchKey;
try {
watchKey = watcher.take();
} catch (InterruptedException e) {
System.err.println(e.getMessage());
return;
}
for (WatchEvent<?> event : watchKey.pollEvents()) {
Kind<?> kind = event.kind();
Object context = event.context();
System.out.println("kind=" + kind + ", context=" + context);
}
if (!watchKey.reset()) {
System.out.println("WatchKey is disabled");
return;
}
}
}
}
Execution result
Description
--You can use WatchService
to monitor changes in the specified Path
.
WatchService watcher;
try {
watcher = FileSystems.getDefault().newWatchService();
...
} catch (IOException e) {
e.printStackTrace();
return;
}
--First, get an instance of WatchService
withFileSystems.getDefault (). newWatchService ()
import static java.nio.file.StandardWatchEventKinds.*;
...
Watchable path = Paths.get("./build");
path.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
--Next, you can start monitoring by passing WatchService
to theregister ()
method of the Watchable
you want to monitor.
--Path
inherits Watchable
, so it can be used as a monitoring target.
--Specify the event you want to monitor after the second argument
--Specify the constants defined in StandardWatchEventKinds
--However, ʻOVERFLOW` does not need to be specified (details will be described later).
while (true) {
WatchKey watchKey;
try {
watchKey = watcher.take();
} catch (InterruptedException e) {
System.err.println(e.getMessage());
return;
}
...
}
--When you execute the take ()
method of WatchService
, it waits for processing until the event to be monitored occurs.
--A WatchKey
object is returned when a monitored event occurs
--WatchKey
is an object that is created when a monitoring target is registered withregister ()
of Watchable
, and it controls the monitoring status such as referencing event information that occurred for each monitoring target and canceling monitoring. it can
for (WatchEvent<?> event : watchKey.pollEvents()) {
Kind<?> kind = event.kind();
Object context = event.context();
System.out.println("kind=" + kind + ", context=" + context);
}
--You can get the information of the event that occurred (WatchEvent
) withpollEvents ()
of WatchKey
.
--The following information can be obtained from WatchEvent
--kind
: Type of event that occurred
--context
: APath
object with a relative path to the created / modified / deleted entry (file or folder)
--count
: Number of times this type of event has occurred
if (!watchKey.reset()) {
System.out.println("WatchKey is disabled");
return;
}
--Finally, execute reset ()
of WatchKey
--Why you have to call reset ()
later
--The return value of reset ()
is boolean
, which tells you if WatchKey
is still valid.
--If false
, the WatchKey
is disabled and monitoring cannot continue.
--One of the following three conditions is applicable for invalidation
WatchKey.cancel ()
WatchService.close ()
canceled monitoring from WatchService
--WatchKey
has two states, READY
and SIGNALLED
.
--When generated by Watchable.register ()
, it is in the READY
state.
--Changes to SIGNALLED
when an event is detected
--When you execute WatchKey.reset ()
, it returns to the READY
state again.
--WatchService
stores the WatchKey
created when you executed Watchable.register ()
.
--Also, it holds a queue filled with only WatchKey
whose status is SIGNALLED
.
--The WatchKey
immediately after it is created is in the READY
state, so it is not in the queue.
--When a monitored event is detected, the status of the corresponding WatchKey
is changed from READY
to SIGNALLED
.
--The WatchKey
whose status is SIGNALLED
is added to the queue of WatchService
.
--Client-side implementations using WatchService
can retrieve WatchKey
at the beginning of the queue by using the WatchService.take ()
or poll ()
methods (removed from the queue). Ru)
--take ()
blocks processing when the queue is empty and waits for WatchKey
to be added to the queue
-- poll ()
returns null
without blocking if the queue is empty
--For poll ()
, you can specify the timeout time as an argument and let it wait until then.
--The WatchKey
that was dequeued withtake ()
orpoll ()
will not be requeued as is.
--The state of WatchKey
removed from the queue is still SIGNALLED
--If an additional monitored event occurs when WatchKey
is SIGNALLED
, it will not be requeued.
--The event information itself that occurred is properly added to WatchKey
--WatchKey
is made thread-safe, so even if event information is added during event processing, the internal state will not be corrupted.
--pollEvents ()
returns a copy of the event information that WatchKey
had at that time.
--In addition, the event information acquired by pollEvents ()
has been deleted from the inside of WatchKey
.
--In short
--Once removed from the queue, WatchKey
will not be queued again if left untouched.
--If you are not in the queue, you cannot retrieve it with take ()
or poll ()
.
That means
--The state must be returned to READY
in order for WatchKey
to be queued again.
--To return the state of WatchKey
to READY
, execute the reset ()
method of WatchKey
.
--If the event information held by WatchKey
is empty (no unprocessed events), the status returns to READY
.
--After that, when another event occurs, it becomes SIGNALLED
and is added to the queue.
--If the event information is not empty (there are unprocessed events), it will be added to the queue in the SIGNALLED
state.
Summary,
--The WatchKey
immediately after creation is in the READY
state.
--If an event is detected and changed to SIGNALLED
, it will be added to the queue in WatchService
.
--You can take WatchKey
from the queue withtake ()
,poll ()
--Once out of the queue, WatchKey
will not return to the queue without permission unless you executereset ()
.
--If there are unprocessed events, they can be queued as SIGNALLED
.
If there are no unprocessed events, it will be in the READY
state, and the next time the monitored event occurs, it will be SENGALLED
again and queued.
package sample.watch;
...
public class Main {
public static void main(String[] args) {
...
while (true) {
WatchKey watchKey;
try {
watchKey = watcher.take();
Thread.sleep(1000);★ Addition
} catch (InterruptedException e) {
...
}
...
}
}
}
Execution result
Description
--A special event called ʻOVERFLOWis used if an event is lost or destroyed for any reason. --For example, depending on the execution environment, there may be an upper limit on the number of events stored in
WatchKey, and when an event that exceeds the upper limit occurs, the ʻOVERFLOW
event is used.
--In the above example, wait for 1 second before getting the event (pollEvents ()
), save all the events of a large number of file generation in WatchKey
, and forcibly generate ʻOVERFLOW. Is --ʻOVERFLOW
event is notified when the condition is met even if it is not specified as an event to be monitored by registration with Watchable.register ()
.
--Therefore, it is better to always consider the processing when ʻOVERFLOW` occurs.
--If you can ignore it, ignore it, if you make an error, make an error (it depends on the application you are making)
package sample.watch;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.Watchable;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.WatchEvent.*;
public class Main {
public static void main(String[] args) {
WatchService watcher;
WatchKey fooKey;
WatchKey barKey;
try {
watcher = FileSystems.getDefault().newWatchService();
Watchable foo = Paths.get("./build/foo");
fooKey = foo.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
Watchable bar = Paths.get("./build/bar");
barKey = bar.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (true) {
WatchKey watchKey;
try {
watchKey = watcher.take();
} catch (InterruptedException e) {
System.err.println(e.getMessage());
return;
}
for (WatchEvent<?> event : watchKey.pollEvents()) {
Kind<?> kind = event.kind();
if (kind == OVERFLOW) {
continue;
}
Object context = event.context();
String directory;
if (watchKey == fooKey) {
directory = "foo";
} else if (watchKey == barKey) {
directory = "bar";
} else {
directory = "unknown";
}
System.out.println("directory=" + directory + ", kind=" + kind + ", context=" + context);
}
if (!watchKey.reset()) {
System.out.println("WatchKey is disabled");
return;
}
}
}
}
Execution result
Description
--One WatchService
can monitor multiple folders
--In that case, it is necessary to identify which folder the WatchKey
obtained byWatchService.take ()
points to.
--If you save the WatchKey
that is returned as the return value ofWatchable.register ()
, you can compare it to identify which folder the event is in.
--Directory change monitoring (Java? Tutorial> Important classes> Basic I / O)
Recommended Posts