Java 7的新特性:文件监视器

介绍一个Java7的新特性,文件监视器。

/**
 * JavaSE7のファイル監視の実験
 * @author aegeanworkjp
 */
public class FWatch_java7 implements Runnable {

    /**
     * 監視先ディレクトリ
     */
    private String dirName;

    /**
     * イベントごとのウェイト時間(秒)
     */
    private int waitCnt;
    
    /**
     * オプションの修飾子
     */
    private WatchEvent.Modifier[] extModifiers;
    
    /**
     * 実行部
     */
    @Override
    @SuppressWarnings({"SleepWhileInLoop", "CallToThreadDumpStack"})
    public void run() {
        try {
            // ファイル監視などの機能は新しいNIO2クラスで拡張されたので
            // 旧File型から、新しいPath型に変換する.
            Path dirPath = new File(dirName).toPath();
            System.out.println(String.format("監視先: %s\n待機時間: %d\n", dirName, waitCnt));

            // ディレクトリが属するファイルシステムを得る
            FileSystem fs = dirPath.getFileSystem();

            // ファイルシステムに対応する監視サービスを構築する.
            // (一つのサービスで複数の監視が可能)
            try (WatchService watcher = fs.newWatchService())
            {
                // ディレクトリに対して監視サービスを登録する.
                WatchKey watchKey = dirPath.register(watcher, new Kind[]{
                    StandardWatchEventKinds.ENTRY_CREATE, // 作成
                    StandardWatchEventKinds.ENTRY_MODIFY, // 変更
                    StandardWatchEventKinds.ENTRY_DELETE, // 削除
                    StandardWatchEventKinds.OVERFLOW},    // 特定不能時
                    extModifiers); // オプションの修飾子、不要ならば空配列

                // 監視が有効であるかぎり、ループする.
                // (監視がcancelされるか、監視サービスが停止した場合はfalseとなる)
                while (watchKey.isValid()) {
                    try{
                        // スレッドの割り込み = 終了要求を判定する.
                        if (Thread.currentThread().isInterrupted()) {
                            throw new InterruptedException();
                        }
                        
                        // ファイル変更イベントが発生するまで待機する.
                        WatchKey detecedtWatchKey = watcher.poll(500, TimeUnit.MILLISECONDS);
                        if (detecedtWatchKey == null) {
                            // タイムアウト
                            System.out.print(".");
                            continue;
                        }
                        System.out.println();

                        // イベント発生元を判定する
                        if (detecedtWatchKey.equals(watchKey)) {
                            // 発生したイベント内容をプリントする.
                            for (WatchEvent event : detecedtWatchKey.pollEvents()) {
                                // 追加・変更・削除対象のファイルを取得する.
                                // (ただし、overflow時などはnullとなることに注意)
                                Path file = (Path) event.context();
                                System.out.println(event.kind() +
                                        ": count=" + event.count() +
                                        ": path=" + file);
                            }
                        }

                        // イベントのハンドリングに時間がかかるケースを
                        // Sleepでエミュレートする.
                        // (この間のファイル変更イベントを取りこぼすか否かを確かめられる)
                        for (int cnt = 0; cnt < waitCnt; cnt++) {
                            System.out.print(String.format("%d/%d...\r", cnt + 1, waitCnt));
                            Thread.sleep(1000);
                        }

                        // イベントの受付を再開する.
                        detecedtWatchKey.reset();
                        
                    } catch (InterruptedException ex) {
                        // スレッドの割り込み = 終了要求なので監視をキャンセルしループを終了する.
                        System.out.println("監視のキャンセル");
                        watchKey.cancel();
                    }
                }
            }
        } catch (RuntimeException | IOException ex) {
            ex.printStackTrace();
        }
        System.out.println("スレッドの終了");
    }
    
    /**
     * 第一引数に監視対象のディレクトリを指定する.
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        // 監視先
        String dirName = "C:\\temp";
        // イベントごとのウェイト
        int waitCnt = 0;
        WatchEvent.Modifier[] extModifiers = new WatchEvent.Modifier[0];
        
        // オプションを解析する.
        int mx = args.length;
        for (int idx = 0; idx < mx; idx++) {
            String arg = args[idx];
            if (arg.startsWith("-w:")) {
                waitCnt = Integer.parseInt(arg.substring(3));
            } else if (arg.equals("-r")) {
                extModifiers = new WatchEvent.Modifier[] {
                    // ファイルツリーを監視する非標準の修飾子
                    // ※ Windows以外では正しく機能しない.
                    com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE
                };
            } else {
                dirName = arg;
                break;
            }
        }
        
        // スレッドの開始
        FWatch_java7 inst = new FWatch_java7();
        inst.dirName = dirName;
        inst.waitCnt = waitCnt;
        inst.extModifiers = extModifiers;
        Thread thread = new Thread(inst);
        thread.start();
        
        // エンターキーが押されるまで実行(コンソールがある場合)
        Console cons = System.console();
        if (cons != null) {
            cons.printf("エンターキーで終了.\n");
            cons.readLine();

            // スレッドへの終了要求と終了待機
            thread.interrupt();
        }

        // スレッド終了まで待機
        thread.join();
        System.out.println("done.");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值