java 1.7watchservice特性學習 文件變動監控

1、首先概述1.7版本上面的這個java.nio.file.WatchService類

1.1 WatchService 能夠幹什麼?

WatchService能夠幫助咱們監控一些文件是否作了更改,若是文件作了更改,能夠幫助咱們去作一些響應,好比,配置文件修改了,那麼系統應該從新加載一下配置文件,這樣能夠將最新的配置加載進來。html

 

1.2 完成文件監控一些很重要的類

The watch service exits when either the thread exits or when it is closed (by invoking its closed method。當前啓動的線程退出或者調用closed方法關閉的時候,watch service也會推出。java

1.2.1 java.nio.file.WatchKey類 

此類表明着一個Object(文件或者文件夾) 註冊到WatchService後,返回一個WatchKey類。反應當前所註冊的Object狀態的類。此類封裝了不一樣事件的狀態值,好比,當文件(文件夾)被修改或者被刪除或者建立的時候,此類首先產生一個信號量,等待消費者來取而且該WatchKey將會進入到WatchService的隊列中。若是WatchKey已經進入到隊列當中,可是又有了變化,將不會再次進入到隊列當中。oracle

WatchService.take()方法能夠取到隊列的WatchKey.app

1.2.2 java.nio.file.Path類

此類表明文件系統上面的一個文件jsp

1.2.2 java.nio.file.WatchEvent類

此類表明文件的一個具體事件。ide

WatchEvent測試

1.3 原理探討(參考

To implement this functionality, called file change notification, a program must be able to detect what is happening to the relevant directory on the file system. One way to do so is to poll the file system looking for changes, but this approach is inefficient. It does not scale to applications that have hundreds of open files or directories to monitor.ui

要作到文件變動提醒功能,有一種辦法就是輪詢文件系統上面的文件確認是否有變動,可是顯然這種作法效率不高。this

The java.nio.file package provides a file change notification API, called the Watch Service API. This API enables you to register a directory (or directories) with the watch service. When registering, you tell the service which types of events you are interested in: file creation, file deletion, or file modification. When the service detects an event of interest, it is forwarded to the registered process. The registered process has a thread (or a pool of threads) dedicated to watching for any events it has registered for. When an event comes in, it is handled as needed.spa

Java WatchService 服務提供API,能夠註冊你感興趣的事件,當service 發現註冊的事件後,就交給處理線程作處理。

1.4 使用注意事項

1.4.1 收到變動事件時候,是否變動已經完成

當收到一個文件變動事件的時候,並不表示該文件已經變動完畢,有可能還在變動當中。

1.4.2 何時使用Watch Service比較好.

The Watch Service API is designed for applications that need to be notified about file change events. It is well suited for any application, like an editor or IDE, that potentially has many open files and needs to ensure that the files are synchronized with the file system. It is also well suited for an application server that watches a directory, perhaps waiting for .jsp or .jar files to drop, in order to deploy them.

This API is not designed for indexing a hard drive. Most file system implementations have native support for file change notification. The Watch Service API takes advantage of this support where available. However, when a file system does not support this mechanism, the Watch Service will poll the file system, waiting for events.

1.5 親自測試

Oracle 官方給出的例子代碼:

package com.hpe.common.audit;


/*
 * 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);
    }
/******************************************
 * 使用方法,能夠傳入兩個參數,
 * 第一個參數表示是否循環遍歷該文件夾(能夠不傳),
 * 第二個參數表明要監控的文件路徑。
 * 
 * @param args
 * @throws IOException
 */

    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();
    }
}

輸出結果:

Scanning E:\work\ftp_file\download ...
Done.
ENTRY_CREATE: E:\work\ftp_file\download\New Text Document.txt
ENTRY_DELETE: E:\work\ftp_file\download\New Text Document.txt
ENTRY_CREATE: E:\work\ftp_file\download\11.txt
ENTRY_MODIFY: E:\work\ftp_file\download\11.txt
ENTRY_MODIFY: E:\work\ftp_file\download\11.txt
 

1.6 其它博文參考

http://codingjunkie.net/java-7-watchservice/

相關文章
相關標籤/搜索