Java 我可以用WatchService监视单个文件的更改吗(不是整个目录)?
当我试图注册一个文件而不是一个目录Java 我可以用WatchService监视单个文件的更改吗(不是整个目录)?,java,watchservice,Java,Watchservice,当我试图注册一个文件而不是一个目录java.nio.file时,会抛出NotDirectoryException。我可以侦听单个文件更改,而不是整个目录吗?只需在目录中筛选所需文件的事件: final Path path = FileSystems.getDefault().getPath(System.getProperty("user.home"), "Desktop"); System.out.println(path); try (final WatchService watchServ
java.nio.file时,会抛出NotDirectoryException
。我可以侦听单个文件更改,而不是整个目录吗?只需在目录中筛选所需文件的事件:
final Path path = FileSystems.getDefault().getPath(System.getProperty("user.home"), "Desktop");
System.out.println(path);
try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
final WatchKey wk = watchService.take();
for (WatchEvent<?> event : wk.pollEvents()) {
//we only register "ENTRY_MODIFY" so the context is always a Path.
final Path changed = (Path) event.context();
System.out.println(changed);
if (changed.endsWith("myFile.txt")) {
System.out.println("My file has changed");
}
}
// reset the key
boolean valid = wk.reset();
if (!valid) {
System.out.println("Key has been unregisterede");
}
}
}
final Path Path=FileSystems.getDefault().getPath(System.getProperty(“user.home”),“Desktop”);
System.out.println(路径);
try(final WatchService WatchService=FileSystems.getDefault().newWatchService()){
final WatchKey WatchKey=path.register(watchService,StandardwatchEventTypes.ENTRY\u MODIFY);
while(true){
final WatchKey wk=watchService.take();
for(WatchEvent事件:wk.pollEvents()){
//我们只注册“ENTRY\u MODIFY”,因此上下文总是一条路径。
最终路径已更改=(路径)event.context();
系统输出打印项次(更改);
if(changed.endsWith(“myFile.txt”)){
System.out.println(“我的文件已更改”);
}
}
//重设钥匙
布尔有效值=wk.reset();
如果(!有效){
System.out.println(“密钥已注销”);
}
}
}
在这里,我们检查更改的文件是否为“myFile.txt”,如果是,则执行任何操作。Apache提供了一个带有doOnChange
方法的类
private class SomeWatchFile extends FileWatchdog {
protected SomeWatchFile(String filename) {
super(filename);
}
@Override
protected void doOnChange() {
fileChanged= true;
}
}
您可以在任何需要的地方启动此线程:
SomeWatchFile someWatchFile = new SomeWatchFile (path);
someWatchFile.start();
FileWatchDog类轮询文件的
lastModified()
时间戳。来自Java NIO的本机WatchService效率更高,因为通知是即时的。不,不可能注册文件,watch服务不能以这种方式工作。但是注册一个目录实际上是监视目录子目录(文件和子目录)的变化,而不是目录本身的变化
如果要监视文件,则向监视服务注册包含该文件的目录。说:
WatchKey java.nio.file.Path.register(WatchService-watcher,Kind[]事件,修饰符。。。
修饰符)引发IOException
向监视服务注册此路径下的文件
在此版本中,此路径定位存在的目录。目录已通过监视服务注册,以便监视目录中的条目
然后,您需要处理条目上的事件,并通过检查事件的上下文值来检测与您感兴趣的文件相关的事件。上下文值表示条目的名称(实际上是相对于其父项路径的条目路径,它正是子项名称)。您有一个。其他答案是正确的,您必须查看目录并筛选特定文件。但是,您可能希望在后台运行线程。接受的答案可以无限期地阻止
watchService.take()代码>并且不关闭WatchService。适用于单独线程的解决方案可能如下所示:
public class FileWatcher extends Thread {
private final File file;
private AtomicBoolean stop = new AtomicBoolean(false);
public FileWatcher(File file) {
this.file = file;
}
public boolean isStopped() { return stop.get(); }
public void stopThread() { stop.set(true); }
public void doOnChange() {
// Do whatever action you want here
}
@Override
public void run() {
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
Path path = file.toPath().getParent();
path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
while (!isStopped()) {
WatchKey key;
try { key = watcher.poll(25, TimeUnit.MILLISECONDS); }
catch (InterruptedException e) { return; }
if (key == null) { Thread.yield(); continue; }
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
@SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
if (kind == StandardWatchEventKinds.OVERFLOW) {
Thread.yield();
continue;
} else if (kind == java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY
&& filename.toString().equals(file.getName())) {
doOnChange();
}
boolean valid = key.reset();
if (!valid) { break; }
}
Thread.yield();
}
} catch (Throwable e) {
// Log or rethrow the error
}
}
}
公共类FileWatcher扩展线程{
私人最终文件;
私有AtomicBoolean停止=新的AtomicBoolean(false);
公共文件监视程序(文件){
this.file=文件;
}
公共布尔值({return stop.get();}
public void stopThread(){stop.set(true);}
公共空间的变化(){
//在这里你想做什么就做什么
}
@凌驾
公开募捐{
try(WatchService watcher=FileSystems.getDefault().newWatchService()){
路径路径=file.toPath().getParent();
注册表(watcher、StandardWatchEventKinds.ENTRY\u MODIFY);
而(!isStopped()){
监视键;
试试{key=watcher.poll(25,TimeUnit.ms);}
catch(InterruptedException e){return;}
如果(key==null){Thread.yield();continue;}
for(WatchEvent事件:key.pollEvents()){
WatchEvent.Kind-Kind=event.Kind();
@抑制警告(“未选中”)
WatchEvent ev=(WatchEvent)事件;
路径文件名=ev.context();
if(kind==StandardWatchEventKinds.OVERFLOW){
螺纹屈服强度();
继续;
}else if(kind==java.nio.file.StandardWatchEventKinds.ENTRY\u MODIFY
&&filename.toString().equals(file.getName()){
doOnChange();
}
布尔有效值=key.reset();
如果(!valid){break;}
}
螺纹屈服强度();
}
}捕获(可丢弃的e){
//记录或重新显示错误
}
}
}
我试着从被接受的答案开始工作。您应该能够将此线程与newfilewatcher(new File(“/home/me/myfile”))一起使用。启动()
并通过调用线程上的stopThread()
来停止它。对其他线程不太确定,但我对使用基本WatchService API监视单个文件的更改所需的代码量感到不满。它必须更简单
以下是使用第三方库的两个备选方案:
- (未立即找到此示例实现,但它期待直接使用)
我围绕Java1.7的监视服务创建了一个包装器,它允许注册目录和任意数量的glob模式。这个类将负责过滤,并且只发出您感兴趣的事件
try {
DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw
watchService.register( // May throw
new DirectoryWatchService.OnFileChangeListener() {
@Override
public void onFileCreate(String filePath) {
// File created
}
@Override
public void onFileModify(String filePath) {
// File modified
}
@Override
public void onFileDelete(String filePath) {
// File deleted
}
},
<directory>, // Directory to watch
<file-glob-pattern-1>, // E.g. "*.log"
<file-glob-pattern-2>, // E.g. "input-?.txt"
<file-glob-pattern-3>, // E.g. "config.ini"
... // As many patterns as you like
);
watchService.start(); // The actual watcher runs on a new thread
} catch (IOException e) {
LOGGER.error("Unable to register file change listener for " + fileName);
}
试试看{
DirectoryWatchService watchService=新建SimpleDirectory watchService();//可能会引发
watchService.register(//可以抛出
新建DirectoryWatchService.OnFileChangeListener(){
@凌驾
公共void onFileCreate(字符串文件路径
import java.io.File;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import static java.nio.file.StandardWatchEventKinds.*;
public abstract class FileWatcher
{
private Path folderPath;
private String watchFile;
public FileWatcher(String watchFile)
{
Path filePath = Paths.get(watchFile);
boolean isRegularFile = Files.isRegularFile(filePath);
if (!isRegularFile)
{
// Do not allow this to be a folder since we want to watch files
throw new IllegalArgumentException(watchFile + " is not a regular file");
}
// This is always a folder
folderPath = filePath.getParent();
// Keep this relative to the watched folder
this.watchFile = watchFile.replace(folderPath.toString() + File.separator, "");
}
public void watchFile() throws Exception
{
// We obtain the file system of the Path
FileSystem fileSystem = folderPath.getFileSystem();
// We create the new WatchService using the try-with-resources block
try (WatchService service = fileSystem.newWatchService())
{
// We watch for modification events
folderPath.register(service, ENTRY_MODIFY);
// Start the infinite polling loop
while (true)
{
// Wait for the next event
WatchKey watchKey = service.take();
for (WatchEvent<?> watchEvent : watchKey.pollEvents())
{
// Get the type of the event
Kind<?> kind = watchEvent.kind();
if (kind == ENTRY_MODIFY)
{
Path watchEventPath = (Path) watchEvent.context();
// Call this if the right file is involved
if (watchEventPath.toString().equals(watchFile))
{
onModified();
}
}
}
if (!watchKey.reset())
{
// Exit if no longer valid
break;
}
}
}
}
public abstract void onModified();
}
import java.io.File;
public class MyFileWatcher extends FileWatcher
{
public MyFileWatcher(String watchFile)
{
super(watchFile);
}
@Override
public void onModified()
{
System.out.println("Modified!");
}
}
String watchFile = System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "Test.txt";
FileWatcher fileWatcher = new MyFileWatcher(watchFile);
fileWatcher.watchFile();