web-dev-qa-db-ja.com

Javaマップされたドライブの監視中にWatchServiceがイベントを生成しない

ファイルウォッチャーを実装しましたが、Java nioファイルウォッチャーは、マップされたドライブにコピーされているファイルのイベントを生成しないことに気付きました。たとえば、Unixでファイルウォッチャーを実行して、ローカルディレクトリ(/sharedfolder)これはWindows(H:\)、そして私はこのディレクトリにファイルを置きました(H:\)しかし、ファイルウォッチャーはイベントを生成していません。ここで、Windowsでファイルウォッチャーを実行して、マップされたドライブをウォッチする場合(H:\)これはUNIXパス(/sharedfolder)そしてunixからこのフォルダにファイルを置くと、ファイルウォッチャーは変更を識別してイベントを生成します。バグのように見えますか、何かが足りないのではないかと思いますか?

25
Ramcis

マウントされたWindows共有をCIFS経由で監視しようとすると同じ問題が発生します。 CIFSマウントのファイルシステムイベント を取得できないようです。

Java 7 NIO FileWatcherのLinux実装はinotifyを使用します。Inotifyはファイルシステムの変更に気付くためのLinuxカーネルサブシステムです。ローカルディレクトリには最適に機能しますが、 CIFSマウント には明らかに機能しません。

Oracleでは、修正することは優先度が高くないようです このバグ 。 (それは彼らの責任ですか?OSの問題の詳細...)

JNotify Linuxシステムでもinotifyを使用するため、これもオプションではありません。

したがって、マップされたドライブの監視は、残念ながらポーラーに限定されているようです。

  • Apache VFS DefaultFileMonitor ディレクトリをポーリングする(マウントされた共有)
  • 標準のJava APIに基づくファイルポーラー。
  • jCIFS のカスタムファイルポーラー(したがって、共有をホストにマウントする必要はありません)

箱から出してファイルの作成、更新、削除を検出するため、おそらくApacheVFSモニターを試してみます。共有をマウントする必要がありますが、それはOSにCIFS接続の責任を与え、私のアプリケーションには責任を与えません。

26
Tim Van Laer

JDKのファイル監視機能は、ネイティブライブラリを使用するためプラットフォームに依存するため、プラットフォームごとに動作が異なる可能性があります。私はそれがネットワークドライブでまったく機能することに驚いています-Windowsはネットワークにマップされたドライブをポーリングして変更を確認する必要がありますが、Linuxはそうではありません(当然のことながらそう言うべきです)。

通常、この種の監視はOS​​カーネルに実装されており、ローカルでどのファイルが変更/作成されているかなどを明らかに知っていますが、OSがネットワークドライブで何が起こっているかを簡単に知る方法はありません。

4
maximdim

私も同じ問題を抱えていました。 de mainクラスで新しいスレッドを作成し、ファイルに定期的にアクセスして新しい変更イベントが発生するようにすることで、これを解決しました。

サンプルは、タッチを行う10秒ごとにdirをポーリングします。

package com.ardevco.files;

import Java.io.IOException;
import Java.nio.file.DirectoryStream;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.Paths;
import Java.nio.file.attribute.FileTime;
import Java.util.ArrayList;
import Java.util.List;

public class Touch implements Runnable {

    private Path touchPath;

    public Touch(Path touchPath) {
        this.touchPath = touchPath;
        this.checkPath = checkPath;

    }

    public static void touch(Path file) throws IOException {
        long timestamp = System.currentTimeMillis();
        touch(file, timestamp);
    }

    public static void touch(Path file, long timestamp) throws IOException {
        if (Files.exists(file)) {
            FileTime ft = FileTime.fromMillis(timestamp);
            Files.setLastModifiedTime(file, ft);
        }
    }

    List<Path> listFiles(Path path) throws IOException {
        final List<Path> files = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
            for (Path entry : stream) {
                if (Files.isDirectory(entry)) {
                    files.addAll(listFiles(entry));
                }
                files.add(entry);
            }
        }
        return files;
    }

    @Override
    public void run() {
        while (true) {
            try {
                for (Path path : listFiles(touchPath)) {
                    touch(path);
                }
            } catch (IOException e) {
                System.out.println("Exception: " + e);
            }

            try {
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                System.out.println("Exception: " + e);
            }
        }

    }

}
3
Mehmet Erdemsoy

私もこれに遭遇し、ここにいる他のすべての人と同じ結論に達しました(CIFS + inotify = nogo)。

しかし、私のワークフローはたまたまinotifyに依存するリモートマウントと自動コンパイルツールの両方に依存していたため、基本的にポーリングを使用して変更を監視し、同じファイルに再度アクセスする(かなり絶望的でハッキーな)ソリューションを構築することになりましたマウントされた側では、inotifyイベントを発生させるようです。それは私の最も誇らしい瞬間ではありません。

そうは言っても、それは機能するので、楽しんでください: http://github.com/rubyruy/watchntouch

1
rubyruy

リモートのWindowsディレクトリにあるログファイルのコンテンツを監視するPythonスクリプトでも同様の問題が発生しました。

これが私の答えです。

Unixからリモートドライブをマッピングする場合は、/etc/fstab 使用する //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

資格情報ファイルを使用して、パスワードがプレーンテキストにならないようにすることができます。

コマンドはunixバージョンに応じて変わる可能性があり、これはdebianでテストされました。意図したとおりに機能するはずです。それが機能するかどうか教えてもらえますか? Javaに同じものを実装する予定なので、答えは私にも役立つかもしれません。

1
1337Wolf