Java windows 7中的Watchservice不工作
这段代码在Linux中运行良好,但在Windows7中不行:要更新文件内容,我必须单击输出文件。诀窍在哪里 我使用的是Windows 7 prof,NetBeans IDE 8.0 RC1(构建版本2014022242200),更新为NetBeans 8.0补丁1.1版,JDK 1.8版Java windows 7中的Watchservice不工作,java,windows,watchservice,Java,Windows,Watchservice,这段代码在Linux中运行良好,但在Windows7中不行:要更新文件内容,我必须单击输出文件。诀窍在哪里 我使用的是Windows 7 prof,NetBeans IDE 8.0 RC1(构建版本2014022242200),更新为NetBeans 8.0补丁1.1版,JDK 1.8版 package watchfilethreadmod; import java.io.FileNotFoundException; import java.io.IOException; import jav
package watchfilethreadmod;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardWatchEventKinds.*;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class WatchFileThreadMod {
static class WatchFile {
String fileName;
long lastFilePos;
RandomAccessFile file;
public WatchFile(String _fileName, RandomAccessFile _file) {
fileName = _fileName;
lastFilePos = 0;
file = _file;
}
}
public static void shutDownListener(Thread thread) {
Thread thr = thread;
if (thr != null) {
thr.interrupt();
}
}
private static class MyWatchQueueReader implements Runnable {
/**
* the watchService that is passed in from above
*/
private WatchService myWatcher;
public ArrayList<WatchFile> threadFileToWatch;
public String dirPath;
public MyWatchQueueReader(String _dirPath, WatchService myWatcher, ArrayList<WatchFile> _threadFileToWatch) {
this.myWatcher = myWatcher;
this.threadFileToWatch = _threadFileToWatch;
this.dirPath = _dirPath;
}
private void openFile(WatchFile obj) {
try {
System.out.println("Open file "+obj.fileName);
obj.file = new RandomAccessFile(dirPath + "/" + obj.fileName, "r");
} catch (FileNotFoundException e) {
obj.file = null;
System.out.println("filename " + obj.fileName + " non trovato");
}
obj.lastFilePos = 0;
}
private void process(WatchEvent evt) {
String thisLine;
ArrayList<WatchFile> auxList = threadFileToWatch;
for (WatchFile obj : auxList) {
if (obj.fileName.equals(evt.context().toString())) {
if (obj.file == null) {
openFile(obj);
}
try {
obj.file.seek(obj.lastFilePos);
} catch (IOException e) {
System.err.println("Seek error: " + e);
}
try {
thisLine = obj.file.readLine();
if ((thisLine == null)&&(evt.kind() == ENTRY_MODIFY)) {
System.out.printf("---> thisLine == null received %s event for file: %s\n",
evt.kind(), evt.context());
obj.file.close();
System.out.println("Close file "+obj.fileName);
openFile(obj);
thisLine = obj.file.readLine();
}
while (thisLine != null) { // while loop begins here
if (thisLine.length() > 0) {
if (thisLine.substring(thisLine.length() - 1).equals("*")) {
obj.lastFilePos = obj.file.getFilePointer();
System.out.println(obj.fileName + ": " + thisLine);
}
}
thisLine = obj.file.readLine();
} // end while
} // end try
catch (IOException e) {
System.err.println("Error: " + e);
}
}
}
}
/**
* In order to implement a file watcher, we loop forever ensuring
* requesting to take the next item from the file watchers queue.
*/
@Override
public void run() {
try {
// get the first event before looping
WatchKey key = myWatcher.take();
while (key != null) {
// we have a polled event, now we traverse it and
// receive all the states from it
for (WatchEvent event : key.pollEvents()) {
WatchEvent.Kind eventType = event.kind();
if (eventType == OVERFLOW) {
continue;
}
process(event);
}
key.reset();
key = myWatcher.take();
}
} catch (InterruptedException e) {
ArrayList<WatchFile> auxList = threadFileToWatch;
for (WatchFile obj : auxList) {
if (obj.file != null) {
try {
obj.file.close();
System.out.println("chiusura file " + obj.fileName);
} catch (IOException ex) {
System.out.println("errore in chiusura file");
Logger.getLogger(WatchFileThreadMod.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
//e.printStackTrace();
}
System.out.println("Stopping thread");
}
}
public static void main(String[] args) throws Exception {
// get the directory we want to watch, using the Paths singleton class
//Path toWatch = Paths.get(DIRECTORY_TO_WATCH);
ArrayList<WatchFile> fileToWatch = new ArrayList<>();
String filename;
RandomAccessFile file;
fileToWatch.add(new WatchFile("EURUSD.rlt", new RandomAccessFile(args[0] + "/EURUSD.rlt", "r")));
filename = "EURCHF2.rlt";
try {
file = new RandomAccessFile(args[0] + "/" + filename, "r");
} catch (FileNotFoundException e) {
file = null;
System.out.println("filename " + filename + " non trovato");
}
fileToWatch.add(new WatchFile(filename, file));
fileToWatch = fileToWatch;
Path toWatch = Paths.get(args[0]);
if (toWatch == null) {
throw new UnsupportedOperationException("Directory not found");
}
// Sanity check - Check if path is a folder
try {
Boolean isFolder = (Boolean) Files.getAttribute(toWatch,
"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder) {
throw new IllegalArgumentException("Path: " + toWatch + " is not a folder");
}
} catch (IOException ioe) {
// Folder does not exists
ioe.printStackTrace();
}
// make a new watch service that we can register interest in
// directories and files with.
WatchService myWatcher = toWatch.getFileSystem().newWatchService();
// start the file watcher thread below
MyWatchQueueReader fileWatcher = new MyWatchQueueReader(args[0], myWatcher, fileToWatch);
Thread processingThread = new Thread(fileWatcher, "FileWatcher");
processingThread.start();
toWatch.register(myWatcher, ENTRY_CREATE, ENTRY_MODIFY);
}
}
编辑4:屏幕广播以更好地显示我的问题:仅当我单击输出文件时数据才会更新
文件路径上可能缺少引号。首先,前提是:我回答这个问题的主要对象是
WatchService
的未来用户,他们(和我一样)可能会遇到这个问题(即,在某些系统上,事件发生后会以信号方式发出)
问题在于,Java中此功能的实现是本机的,因此它依赖于平台(请参阅“平台依赖性”一节)
特别是,在Windows 7(和MacOSX afaict)上,实现使用轮询从文件系统检索更改,因此您不能依赖WatchService
发出的通知的“生动性”。通知最终会发出信号,但无法保证何时会发生。
对于这个问题,我没有一个严格的解决方案,但经过大量的尝试和错误,我可以描述什么适合我:
首先,在写入已注册的文件(即“监视”)时,我会尝试每次刷新内容并更新文件上的“上次修改”属性,例如:
try (FileWriter writer = new FileWriter(outputFile)) {
writer.write("The string to write");
outputFile.setLastModified(System.currentTimeMillis());
writer.flush();
}
其次,我尝试从代码中“触发”刷新(我知道这不是好代码,但在这种情况下,我很高兴它99%的时间都能工作)
或者(如果在outputDir
中查看对特定文件的ENTRY\u MODIFY
)
在这两种情况下,一个
sleep
调用只是给了WatchService
底层机制触发的时间,即使2秒可能比需要的时间多得多。Java是平台独立的:)如果你能告诉我们你得到的错误就好了。我知道Java是平台独立的;我没有任何错误,只有当我点击输出文件时,它才会得到更新。这个问题与操作系统有关,因为在Linux中,同样的代码可以完美地工作。我认为您应该减少这个问题,并创建一个SSCCE。代码太多了。。。我敢打赌,很大一部分与根本问题无关。TL;博士Java上的WatchService
可以在Windows 7上正常工作——我已经编写了一些应用程序,利用它工作,在文件发生更改时检测它们。您可能遇到的两个最有可能的问题是:(1)文件夹虚拟化问题,其中写入将进入%APPDATA%\Local\VirtualStore
的某个位置;或者(2)不同的写入机制,不会改变文件上的更新日期。要允许在记事本中写入,请使用文件共享\写入MetaTrader打开文件。您可以尝试重构MetaTrader代码,使其打开、查找文件末尾、附加新数据,然后在OnTick中关闭文件。您注释掉了这样做的代码(使用FileSeek(file\u handle,0,SEEK\u END);
而不是任何FileRead)。您的问题最有可能出现在MetaTrader端的文件编写机制上,而不是java端。“点击”效应很可能是其他软件(如防病毒软件)的副作用。我刚刚编辑了我的问题,添加了文件pathjava-jar“C:\Users\utente\Desktop\WatchFileThreadMod\dist\WatchFileThreadMod.jar”“C:\Program Files(x86)\MT4 Exchange\MQL4\Files\Data”的图片
try (FileWriter writer = new FileWriter(outputFile)) {
writer.write("The string to write");
outputFile.setLastModified(System.currentTimeMillis());
writer.flush();
}
Thread.sleep(2000);
// in case I've just created a file and I'm watching the ENTRY_CREATE event on outputDir
outputDir.list();
Thread.sleep(2000);
outputFile.length();