ファイル ウォッチャーを実装しましたが、Java nio ファイル ウォッチャーが、マップされたドライブにコピーされているファイルのイベントを生成しないことに気付きました。たとえば、Unix でファイル ウォッチャーを実行して、/sharedfolder
Windows ( ) にマップされているローカル ディレクトリ ( ) を監視しH:\
、このディレクトリ ( H:\
) にファイルを配置しましたが、ファイル ウォッチャーはイベントを生成しませんでした。 . ここで、Windows でファイル ウォッチャーを実行しH:\
て、UNIX パス ( /sharedfolder
) を参照するマップされたドライブ ( ) を監視し、Unix からこのフォルダーにファイルを配置すると、ファイル ウォッチャーは変更を識別し、イベントを生成します。バグのように見えますか、何かが足りないのではないでしょうか?
5 に答える
マウントされた Windows 共有を CIFS 経由で監視しようとすると、同じ問題が発生します。CIFS マウントのファイルシステム イベントを取得できないようです。
Java 7 NIO FileWatcher の Linux 実装はinotifyを使用します。inotify は、ファイルシステムの変更を通知するための Linux カーネル サブシステムであり、ローカル ディレクトリでは完璧に機能しますが、明らかにCIFS マウントでは機能しません。
オラクルでは、このバグを修正する優先度は高くないようです。(それは彼らの責任ですか?OSの問題の詳細...)
JNotifyは Linux システムでもinotifyを使用するため、これもオプションではありません。
残念ながら、マップされたドライブの監視はポーラーに限定されているようです。
- ディレクトリをポーリングするApache VFS DefaultFileMonitor (マウントされた共有)
- 標準 Java API に基づくファイル ポーラー。
- jCIFSを使用したカスタム ファイル ポーラー(ホストに共有をマウントする必要がないため)
ファイルの作成、更新、削除をすぐに検出できるので、おそらく Apache VFS Monitor を試してみます。共有をマウントする必要がありますが、それにより、OS はアプリケーションではなく CIFS 接続の責任を負います。
JDK のファイル監視機能は、ネイティブ ライブラリを使用するため、プラットフォームに依存するため、異なるプラットフォームでは異なる動作をする可能性があります。ネットワークドライブでまったく機能することに驚いています-Windowsはネットワークにマップされたドライブに変更をポーリングする必要がありますが、Linuxはそうではありません(当然のことです)。
通常、この種の監視は OS カーネルに実装されており、どのファイルがローカルで変更/作成/などされているかを明らかに知っていますが、ネットワーク ドライブを排他的に制御できないため、OS がネットワーク ドライブで何が起こっているかを知る簡単な方法はありません。
私も同じ問題を抱えていました。メインクラスに新しいスレッドを作成し、定期的にファイルに触れて、新しい変更イベントが発生するようにすることで解決しました。
サンプルは、10 秒ごとにディレクトリをポーリングして、タッチを行います。
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);
}
}
}
}
私もこれに遭遇し、ここにいる他のみんなと同じ結論に達しました (CIFS + inotify = no go)。
しかし、私のワークフローはたまたま inotify に依存するリモート マウントと自動コンパイル ツールの両方に依存していたため、基本的にポーリングを使用して変更を監視し、同じファイルに再度アクセスする (かなり絶望的でハックな) ソリューションを構築することになりました。マウントされた側で、inotify イベントを発生させているようです。それは私の最も誇りに思う瞬間ではありません。
そうは言っても、うまくいくので、楽しんでください:http://github.com/rubyruy/watchntouch
リモートの Windows ディレクトリにあるログ ファイルの内容を監視する Python スクリプトで同様の問題が発生しました。
これが私の答えです。
Unix からリモートドライブをマッピングする場合は/etc/fstab
、//xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0
資格情報ファイルを使用して、パスワードがプレーン テキストにならないようにすることができます。
コマンドは、UNIX のバージョンによって異なる可能性があります。これは、debian でテストされています。意図したとおりに動作するはずです。それが機能するかどうか教えてもらえますか? 私はJavaで同じものを実装することを計画しているので、答えは私にも役立つかもしれません.