Introduction to the

1.1 introduction

Every time any changes are made to the files, they are automatically refreshed — a very common problem in most applications. Each application has some configuration that is expected to be refreshed with each change in the configuration file. Past approaches to this issue have included using Thread to periodically poll for file changes based on the “last updated timestamp” of the configuration file. Java has introduced a nice feature since JDK1.7: the WatchService class, which can be used to monitor file system changes. WatchService is regarded as a file monitor, running through the operating system native file system, can monitor the changes of all the system files, this monitoring is no traversal, no comparison, is a signal based monitoring.

1.2 features

WatchService monitors files based on the local operating system and dynamically obtains file changes without restarting the system.

1.3 applications

  • For example, the configuration file in the system is usually loaded only once when the system starts. The WatchService can be used to dynamically modify the configuration file without restarting the system.
  • Monitor file changes on disks and use WatchService to monitor files in real time.

Key interfaces, classes, and methods

2.1 Key Interfaces

  • java.nio.file.WatchService: Listening service
    • Is an internal SERVICE of the JDK that monitors changes to registered objects that must be instances of the Watchable interface.
    • Extended the Closeable interface to indicate that the service can be turned off when needed. In general, this should be done using the shutdown hooks provided by the JVM.
public interface WatchService extends Closeable {
	/ * * * * /
    void close(a) throws IOException;
    /** * attempts to get the next listener result and returns null if no changes */
    WatchKey poll(a);
    /** * attempts to get the next listener result, waits at most the specified time, returns null */ if nothing changes
    WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException;
    /** * wait for the next listen, and wait */ if there is no change
    WatchKey take(a) throws InterruptedException;
}
Copy the code
  • The listener service can be obtained as follows:FileSystems.getDefault().newWatchService();
  • Take if you want to monitor over a long period of time, or poll if you want to monitor only at a given time
  • Java.nio.file. WatchEvent: Listen for events
public interface WatchEvent<T> {
    /** * Type of listener event */
    Kind<T> kind(a);

    /** * Number of events, greater than 1 indicates a repeating event */
    int count(a);

    /** * Event context *@returnReturns the relative path */ of the file or directory from which the event was triggered
    T context(a);
}
Copy the code
  • Java.nio.file. WatchKey: listening key
  • The WatchKey object contains a collection of properties for the events that the file changes, known as the monitor information pool, and all the changes are imported into the monitor pool when the file changes.
  • The monitor pool is static, and updates are added to the monitor pool only when you proactively obtain a new monitor pool. This causes the problem that the system may take a little longer to receive the monitoring message event.
public interface WatchKey {
    /** * Whether the key is valid,true: valid, false: invalid */
    boolean isValid(a);

    /** * Pull and delete the (possibly empty) list of listener events located at this listener key */List<WatchEvent<? >> pollEvents();/** * The WatchService key is reset. After the key is reset, the new pending event will enter the listener again. Return true: the key is valid and the reset is successful
    boolean reset(a);

    /** * Cancel listening service for key */
    void cancel(a);

    /** * Returns the Watchable */ associated with this key
    Watchable watchable(a);
}
Copy the code
  • Java.nio.file. Watchable: Listen for registration
public interface Watchable {

    /** * Register listener, including listener service, listener event, listener modification */
    WatchKey register(WatchService watcher,WatchEvent.Kind
       [] events,WatchEvent.Modifier... modifiers)
        throws IOException;


    /** * Listener registration, including listener services and listener events */
    WatchKey register(WatchService watcher, WatchEvent.Kind
       ... events)  throws IOException;
}

Copy the code

2.2 the key class

Blog.csdn.net/weixin_3856…

  • java.nio.file.FileSystems
methods instructions
FileSystem getDefault() Return the default file system,
FileSystem getFileSystem(URI uri) Returns a reference to an existing FileSystem.

If you can’t find the corresponding FileSystem already in existence, will throw an exception ProviderNotFoundException.
FileSystem newFileSystem(Path path,ClassLoader loader) Builds a file system to access the contents of files specified by path.
FileSystem newFileSystem(URI uri, Map<String,? > env) Create an information file system based on the URI.

If you can’t find the corresponding FileSystem already in existence, will throw an exception ProviderNotFoundException.
FileSystem newFileSystem(URI uri, Map<String,? > env, ClassLoader loader) Same as above.
  • java.nio.file.FileSystem

methods instructions
Iterable getFileStores() Returns an Iterable that iterates through the filestores of the file system
Path getPath(String first, String… more) Concatenate the string into a Path and generate an instance of the Path based on the Path
PathMatcher getPathMatcher(String syntaxAndPattern) Returns aPathMatcher
Iterable getRootDirectories() Return an Iterable to traverse the path to the root directory
String getSeparator() Returns the name delimiter as a string
boolean isOpen() Check whether the file system is open
boolean isReadOnly() Determine that the file stores of the file system are read-only
WatchService newWatchService() Building a new WatchService (optional operation)
FileSystemProvider provider() Returns the provider that created this file system
void close() Close the file system. Calling this method has no effect if the file system is already closed
  • java.nio.file.Path
    • The interface defined in JDK1.7 is used to locate files in the file system. It usually represents the file path related to the system.
    • Path in Java indicates the Path of a file system. It can be a relative or absolute Path to a file or folder. The absolute path indicates the path from the root path of the file system to a file or folder, while the relative path indicates the path from a specific path to a specified file or folder.
    • In many ways,java.nio.file.Pathjava.io.FileThere are similarities, but there are also some subtle differences. In many cases, you can replace the File class with Path.
methods instructions
boolean endsWith(Path other)
boolean endsWith(String other)
Path getFileName() Gets the name of a file, directory, or other type of file
FileSystem getFileSystem() Obtaining a File System
Path getName(int index) Loop through the name of each element
int getNameCount() Gets the number of path levels
Path getParent() Gets the Path instance of the parent Path of the file
Path getRoot() Obtaining the root path
boolean isAbsolute() Determine whether the path is an absolute path, that is, whether the actual file can be located based on the path.

Note that an absolute path returns true even if the file does not exist
Iterator iterator() Returns an iterator to access each level of the path
Path normalize() Normalize the file path, remove excess parts in the path, and point to the real path directory address
Path relativize(Path other) Returns a relative path, which is the relative path of path1 based on path
Path resolve(Path other) Take the current path as the parent path, take the input parameter path as the child path, get a new path.
Path resolve(String other) Take the current path as the parent path, take the input parameter path as the child path, get a new path.
Path resolveSibling(Path other) Will replace the current path according to the given path
Path resolveSibling(String other) Will replace the current path according to the given path
boolean startsWith(Path other)
boolean startsWith(String other)
Path subpath(int beginIndex, int endIndex) Get the subpath
Path toAbsolutePath() Convert a relative path to an absolute path
File toFile() Convert to a File object
Path toRealPath(LinkOption… options) Convert to a real path
URI toUri()
  • java.nio.file.Paths
    • Is a static utility class defined in JDK1.7 that returns an instance of Path based on a Path or URI in String format
methods instructions
Path get(URI uri) Creating a Path Instance
Path get(String first, String… more) Accepts one or more strings, between stringsAutomatically usingDefault file system path delimiter.

(/ for Unix, \ for Windows)
  • When using relative paths, you can use two symbols:
    • . : indicates the current path
    • . : indicates the directory of the parent class

Third, the sample

3.1 Points to Note

  • The path.get (path).register method only monitors changes in files under the path file, not in subdirectories.
  • Each take()\poll() operation will cause the thread monitor to block, each operation on the file may take a long time, and will cause the event to be lost if other events occur in the listening directory.
  • WatchKey is called every time the file changes after reading throughreset()Method can continue to read the changes.

3.2 the sample

The operation process of monitoring directory files is as follows:

  1. Get WatchService
  2. Registers the monitor WatchService for the specified directory
  3. Wait for files in the directory to change
  4. Perform operations on the changed file

The following example shows how to monitor file changes in directories and subdirectories and print the changes:

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import java.util.*;

import static com.sun.jmx.mbeanserver.Util.cast;

/** * Take today's best performance as the latest starting point for tomorrow... ~ * <p> * Today the best performance as tomorrow newest starter! * * @Class description: Java added the WatchService class from JDK1.7, which can be used to monitor file system changes. *@author: <a href="mailto:[email protected]"> </a> * @@since: the JDK 1.8 * /
public final class WatchServiceHelper {
	/** * Java listener file **@paramRootPath Directory of the monitored file (only the monitored directory) */
	public static void watcherFile(String rootPath) throws Exception {
		File root = new File(rootPath);
		if(! root.isDirectory()) {throw new Exception("Monitor directory changes only");
		}
// WatchService is like a file monitor. Use the following method to create a listener service
		WatchService watcher = FileSystems.getDefault().newWatchService();


		// Set all directories
		Set<String> pathSet = new LinkedHashSet<>();
		// Look for subdirectories recursively
		loopDir(root, pathSet);

		// Maintain a mapping between WatchKey and directory to find the directory of the changed file.
		Map<WatchKey, String> watchKeyPathMap = new HashMap<>();

		// After the monitor is created, you need to bind it to a directory and specify what changes to monitor
		Kind[] kinds = {
				// Add or rename a directory
				StandardWatchEventKinds.ENTRY_CREATE,
				/ / modify
				StandardWatchEventKinds.ENTRY_MODIFY,
				// Delete or rename
				StandardWatchEventKinds.ENTRY_DELETE
		};
		// Iterate to add monitoring
		for (String path : pathSet) {
			// Listen for registration, listen for entity creation, modification, deletion events
			WatchKey key = Paths.get(path).register(watcher, kinds);
			watchKeyPathMap.put(key, path);
		}

		while (true) {
			// Get the next file change event
			WatchKey watchKey = watcher.take();
			// If the listening key is null, skip
			if (watchKey == null) {
				continue;
			}

			// Get a list of listener events using the key.pollevents () methodList<WatchEvent<? >> watchEventList = watchKey.pollEvents();// Get the listener event
			watchEventList.forEach(watchEvent -> {
				// Get the listener event type
				Kind kind = watchEvent.kind();
				// If the event is abnormal, skip it
				if(StandardWatchEventKinds.OVERFLOW ! = kind) {// Get the name of the file/directory to listen to
					Path path = cast(watchEvent.context());
					// Output the event type, file path and name
					String msg = String.format("Change type: %s, monitor directory: %s, change object: %s", kind.name(), watchKeyPathMap.get(watchKey), path.toString()); System.out.println(msg); }});// After the listening key is processed (that is, after the listening event is processed), the listening key needs to be reset for the next listening
			boolean valid = watchKey.reset();
			// If the reset fails, exit the listen
			if(! valid) {break; }}// Add a JVM closed hook to turn off the listener
		Runtime.getRuntime().addShutdownHook(new Thread(() -> {
			try {
				watcher.close();
			} catch(IOException e) { e.printStackTrace(); }})); }/** * recursively find subdirectories **@paramParent Parent directory *@paramPathSet Set of paths */
	private static void loopDir(File parent, Set<String> pathSet) {
		if(! parent.isDirectory()) {return;
		}
		pathSet.add(parent.getPath());
		for(File child : Objects.requireNonNull(parent.listFiles())) { loopDir(child, pathSet); }}}Copy the code