Junior sister learning java IO: file system and watchservice
brief introduction
Younger martial sister encountered the problem of monitoring file changes this time. Elder martial brother f introduced the watchservice introduced in JDK7 NiO to younger martial sister. Unexpectedly, he popularized the concept of file system on the way. I never thought of it.
Monitoring pain points
Younger martial sister: elder martial brother F, have you felt a little difficult to breathe recently, a little chilly in the back, and a little difficult to speak?
No, younger martial sister, are you wearing autumn clothes upside down?
Younger martial sister: No, elder martial brother F, what I'm talking about is the feeling in my heart, the kind of unnecessary pressure, and a trace of palpitation.
Don't beat around the Bush, younger martial sister. Are you having problems again.
More highlights:
Younger martial sister: Senior brother f still understands me. I'm not very good at using the properties file last time. It's really painful to restart the Java application every time you modify the properties file. Is there any other way?
Of course, there are ways. The most basic way is to open a thread to regularly monitor the last modification time of the property file. If it is modified, it will be reloaded. This is not OK.
Younger martial sister: writing threads is so troublesome. Is there any simpler way?
I knew you wanted to ask. Fortunately, I've prepared enough. Today I'll introduce you to a watchservice class introduced by JDK7 in NiO.
Watchservice and file system
Watchservice is an interface introduced by JDK7 in NiO:
The monitored service is called watchservice, and the monitored object is called Watchable:
WatchKey register(WatchService watcher,WatchEvent.Kind<?>[] events,WatchEvent.Modifier... modifiers)
throws IOException;
WatchKey register(WatchService watcher,WatchEvent.Kind<?>... events)
throws IOException;
Watchable registers the watchevent of the object to the watchservice through register. Since then, as long as a watchevent occurs on the Watchable object, the watchservice will be notified.
There are four types of watchevent:
The watchkey returned by register is the collection of monitored watchevents.
Now let's look at the four methods of watchservice:
Younger martial sister: Senior brother F, how can we build a watchservice?
Younger martial sister, remember the file system mentioned in the last article. There is a method to obtain watchservice in the file system:
public abstract WatchService newWatchService() throws IOException;
Let's take a look at the structure diagram of the file system:
On my Mac system, file systems can be divided into three categories: unixfilesystem, jrtfilesystem and zipfilesystem. I guess there should be a corresponding windows related file system on windows. Younger martial sister, you can have a look if you are interested.
Junior sister: Unix file system is used to process files under UNIX, and zipfilesystem is used to process zip files. What is jrtfilesystem used for?
Oh, it's going to be far away. Why does it bring questions to the horizon every time
In the past, when JDK was 9, a very big change was made called modular jpms (Java platform module system). This JRT is for modular systems. Let's take an example:
public void useJRTFileSystem(){
String resource = "java/lang/Object.class";
URL url = ClassLoader.getSystemResource(resource);
log.info("{}",url);
}
In the above code, we get the URL of the class object. Let's see what the output is in jdk8:
jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/Object.class
The output result is jar: file, indicating that the object class is placed in the jar file, followed by the path of the jar file.
If after jdk9:
jrt:/java.base/java/lang/Object.class
The result starts with JRT, Java Base is the name of the module, followed by the path of object. It seems that it is more concise than the traditional jar path.
With a file system, we can obtain the corresponding watchservice while obtaining the default file system of the system:
WatchService watchService = FileSystems.getDefault().newWatchService();
Use and implementation essence of watchservice
Younger martial sister: Senior brother F, how did watchserve come true? It's so magical that it saves us so much work.
In fact, JDK provides so many classes to prevent us from building wheels again. I told you before that the easiest way to monitor files is to open an independent thread to monitor file changes? Actually That's what watchservice does!
PollingWatchService() {
// TBD: Make the number of threads configurable
scheduledExecutor = Executors
.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(null,r,"FileSystemWatcher",false);
t.setDaemon(true);
return t;
}});
}
The above method is to generate watchservice. Younger martial sister, do you see it? Its essence is to start a daemon thread to receive monitoring tasks.
Here's how to register a file with watchservice:
private void startWatcher(String dirPath,String file) throws IOException {
WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get(dirPath);
path.register(watchService,ENTRY_MODIFY);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
watchService.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}));
WatchKey key = null;
while (true) {
try {
key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context().toString().equals(fileName)) {
loadConfig(dirPath + file);
}
}
boolean reset = key.reset();
if (!reset) {
log.info("该文件无法重置");
break;
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
The key method above is path Register, where path is a watchable object.
Then use watchservice Take to obtain the generated watchevent, and finally process the file according to the watchevent.