为什么目录WatchService在我更改文件

时间:2015-10-15 20:55:36

标签: java watchservice

我有一个简单的Java实用程序类,它可以观察我注册的目录。我的目标:每当文件在该目录中发生变化时,我想捕获该事件并处理该文件......

我只为ENTRY_MODIFY事件注册了一个目录 - 这个全部在我的本地Windows 7计算机上运行,​​运行时为1.8.0_510-b16。

我启动程序,启动监控过程。然后我更改了该目录中的文件,它识别出更改,但由于某种原因,它产生的不是一个而是两(2)个通知事件 - 对于同一个文件,两者都是相同的ENTRY_MODIFY类型,为什么会这样做?

为方便起见,这是我的完整代码:

package com.xxx.yyy.zzz.lcm;

//import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
//import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
//import java.util.Arrays;

/**
 *  This program uses Java 7 java.nio.* package to Watch for CHANGEs on a set of files that you specify at
 *  startup using command line arguments
 *
 *  Whenever a registered file is changed, the code will Copy that file to a target directory
 *  and give it a new name using the following pattern:
 *  Copy sourcefilepath/eventfilename to targetfilepath/yyyymmdd:HHmmssSSS_eventfilename
 */
public class FileWatcher {

    public static void main(String[] args) {
        // Make sure argument list is not empty
        if (args.length == 0){
            System.out.println("You must specify proper arguments for this utility to run");
            useage();
        }
        /*
         *  Prolog - get the arguments specified
         *  First argument is the targetDir
         *  Arguments 2nd, 3rd, etc fieles to be monitored
         */
        String targetDirArg = args[0];
        String[] filesForMonitoring = new String[args.length - 1]; //
        // Strip off the first entry from the arguments (that's target)
        for(int i=1; i < args.length; i++) {
                filesForMonitoring[i-1] = args[i];
        }
        // Simple Edits:
        if (targetDirArg == null) {
            System.out.println("Target directory you specified ('" + targetDirArg + "') + was not valid.");
            useage();
        }

        if (filesForMonitoring.length < 1) {
            System.out.println("You must specify at least one (or more) files to monitor using command line arguments\n");
            useage();
        }

        // Printout the runtime specs
        System.out.println("*** Runtime Parms ***");
        System.out.println("Target directory:");
        System.out.println("\t" + targetDirArg);

        System.out.println("Filepaths to be watched:");
        for (int i=0; i < filesForMonitoring.length; i++) {
            System.out.println("\t" + filesForMonitoring[i]);
        }


        // Now create the WatcherServices and watch the specified assets
        /*
         * TO-DO Test it thoroughly and figure out why it sometimes produces 2 or 3 events for a single file change
         * I have seen this numerous times but have not been able to reproduce consistently, but I've observed that
         * when monitoring a single file, if I make a change to that file, sometimes that change will produce 2 or
         * even 3 separate events, which is unusual and we need to find out why it's happening.
         */
        try {
            // Create the WatchService object
            WatchService watcher = FileSystems.getDefault().newWatchService();

            // Register the directory path that you want to monitor
            // TO-DO:  Modify this logic to register multiple files (if more than one specified) for monitoring
            Path sourceDir = Paths.get(filesForMonitoring[0]);
            sourceDir.register(watcher, ENTRY_MODIFY);

            System.out.println("\nWatchService watching for file changes in dir: " + sourceDir.getParent() + "\\" + sourceDir.getFileName());
            /*
             * This infinite loop that monitors the specified directory
             * Each directory that is registered will produce a watch key if changed
             */
            while (true) {
                WatchKey key;
                try {
                    key = watcher.take();
                } catch (InterruptedException ex) {
                    return;
                }

                /*
                 * For each directory modified, find out the Events
                 * (there may be multiple events) and the file name, 
                 * then process accordingly
                 * TO DO:  Find out WHY there are sometimes multiple events
                 * for a single filename.... this is problematic
                 */
                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();

                    // Get the Event kind and the filename for that Event
                    @SuppressWarnings("unchecked")
                    WatchEvent<Path> ev = (WatchEvent<Path>) event;
                    Path eventFileName = ev.context();

                    System.out.println("\n" + kind.name() + ": " + eventFileName);

                    // This is how we can check for a change to the specific file
                    if (kind == ENTRY_MODIFY &&
                            eventFileName.toString().endsWith(".properties")) {
                            System.out.println("Content of property file '" + eventFileName.toString() + "' has changed!!!");
                            try {
                                processFile(Paths.get("C:sourcefile"), Paths.get("C:targetfile"));
                            } catch (IOException iox) {
                                iox.printStackTrace();
                            }
                    }
                }
                /*
                * The reset() method is very important to ensure flow of events
                * The only time it may be invalid is if the monitored directory got deleted
                */
                boolean valid = key.reset();
                if (!valid) {
                    break;
                }
            }

        } catch (IOException ex) {
            System.err.println(ex);
        }
    }

    private static void processFile(Path source, Path target) throws IOException {
        System.out.println("Processing file change.  Source='" + source.getFileName() + "', Target=" + target.getFileName() + "'");
    }
    public static void useage() {
        System.out.println("Useage: prompt>java FileWatcher c:/targetdir c:/sourcepath1/sourcefile1.txt c:/sourcepath1/sourcefile2.txt");
        System.out.println("\t The above command would monitor sourcefile1.txt and sourcefile2.txt for any changes");
        System.out.println("\t If any change to one of those files, the code would copy the conents of the changed file(s) from");
        System.out.println("\t sourcepath1 to the target path specified in args[0].   The target file would also be given a new name with timestamp");

        System.exit(1);
    }
}

0 个答案:

没有答案