我正在使用JDK7"观看变更目录"特征。但我发现有时它会给我错误的文件路径,用于存档的特定事件。即使文件名是正确的。我在 fedora和ubuntu 中遇到了这个问题 还有其他人遇到过同样的问题。
重现的步骤:
从https://dl.dropboxusercontent.com/u/39897681/code/fileOperation.zip下载并解压缩以生成文件。请通过阅读README.txt
通过提供空的源文件夹和文件[用于日志目的]作为输入来运行Sample Java代码。等待一段时间
通过配置下载内容运行Main.py,使其生成文件和文件夹。
java程序将显示磁盘上但不在列表中的文件列表[从监视目录收到的文件事件生成的列表]
最初java输出就是没有事件丢失
节目输出 待处理文件数= 2398 没有文件丢失
#但是我们最终错过了一些文件事件或者在一段时间后错误路径
待处理文件数= 4552
findFilesPresentOnDiskButNotInList
错过的文件是 /data/home/developer/test/folder_0.689628351684/folder_0.0451760705904/folder_0.000447662431096/folder_0.264689686702/folder_0.849536150754/folder_0.216092330336/folder_0.677792564103/folder_0.796242073532
#这里使用绝对路径/data/home/developer/test/folder_0.689628351684/folder_0.0451760705904创建folder_0.0451760705904,但是在日志文件中它正在打印文件夹的其他路径。
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.AccessDeniedException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class DirectoryWatcher implements Runnable {
// list of files whose events were received during creation,modification and delete operation
public static List<String> filesList = new ArrayList<String>();
// list of source folder path that we want to monitor
public static List<Path> srcPaths;
private WatchService watcher;
private Map<WatchKey, Path> keys;
private String module = "DirectoryWatcher-";
private boolean trace = false;
FilesetSimpleFileVisitor SFRFileVisitor = new FilesetSimpleFileVisitor();
/**
* Points to the log file which contains all the information about the
* events received by directory watcher. Any event that is received by
* directory watcher is logged into this file with the type of event. eg
* CREATE <full file path>
*/
public static String LOG_FILE_PATH = null;
public static PrintWriter logFileWriter = null;
public DirectoryWatcher(List<Path> srcPaths) throws IOException {
super();
this.srcPaths = srcPaths;
initWatchService();
registerTopLevelSrcFolder();
new Thread(this).start();
}
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>) event;
}
private void initWatchService() throws IOException {
watcher = FileSystems.getDefault().newWatchService();
keys = Collections.synchronizedMap(new HashMap<WatchKey, Path>());
}
private void registerTopLevelSrcFolder() throws IOException {
for (Path dir : srcPaths) {
try {
// logger.print(logger.INFO, logger.PFR,
// "registerTopLevelSrcFolder",
// "Top level directory to be registered is " + dir);
System.out.println("Top level directory to be registered is "
+ dir);
register(dir);
// doScan(dir);
// scanAllFilesOnly(dir);
} catch (AccessDeniedException e) {
e.printStackTrace();
} catch (NoSuchFileException e) {
e.printStackTrace();
}
}
}
/**
* Exception Register the given directory with the WatchService
*/
private void register(Path dir) throws IOException {
final String subModule = module + "register";
File file = dir == null ? null : dir.toFile();
if (file == null || !file.exists()) {
return;
}
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE,
ENTRY_MODIFY);
if (trace) {
Path prev = keys.get(key);
if (prev == null) {
} else {
if (!dir.equals(prev)) {
addToScannedListOnDirRename(file, true);
}
}
}
keys.put(key, dir);
}
/**
* On rename of a directory it adds all the child folders and files.
*
* @param dir
* @throws PFRScanFailedException
*/
/**
* On rename of a directory it adds all the child folders and files.
*
* @param dir
* @throws PFRScanFailedException
*/
private void addToScannedListOnDirRename(File dir, boolean rename)
throws IOException {
// System.out.println("addToScannedListOnDirRename" + dir);
String subModule = module + "addToScannedListOnDirRename";
try {
if (dir.isDirectory()) {
if (!rename) {
try {
register(Paths.get(dir.getAbsolutePath()));
} catch (NoSuchFileException e1) {
// consume.
}
}
File[] files = dir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file == null) {
continue;
}
// doScan(file);
if (file.isDirectory()) {
addToScannedListOnDirRename(file, rename);
}
}
}
} finally {
}
}
boolean closed = false;
private String uniqueFSName = "directoryWatcher";
public void close() {
if (closed) {
return;
}
String subModule = module + "close";
try {
if (watcher != null) {
watcher.close();
}
} catch (IOException e) {
} finally {
freeResources();
}
closed = true;
}
private void freeResources() {
watcher = null;
if (keys != null) {
keys.clear();
}
// logger.print(logger.VERBOSE, logger.PFR,
// "DirectoryWatcher-freeResources ",
// "end of Directory Watcher. Freeing up resources");
}
private void DirectoryWatcherCore() {
String subModule = module + "DirectoryWatcherCore";
// enable trace after initial registration
trace = true;
for (;;) {
// wait for key to be signalled
try {
WatchKey key = null;
try {
key = watcher.take();
} catch (InterruptedException x) {
x.printStackTrace();
return;
} catch (ClosedWatchServiceException x) {
x.printStackTrace();
return;
}
if (key == null) {
System.out.println("key is nulllllllllllllllllllllll");
}
Path dir = keys.get(key);
// System.out.println("**********" + dir);
if (dir == null) {
// logger.print(logger.ERROR, logger.PFR, subModule,
// "WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
final WatchEvent.Kind kind = event.kind();
if (kind == OVERFLOW) {
logFileWriter.println("OVERFLOW");
System.out
.println("XXXXXXXXXXXXXXXXXXX----->>>OVERFLOW<<<--------XXXXXXXXXXXXXXXXXXX");
// triggerFullScan();
continue;
}
// Context for directory entry event is the file name of
// entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
File childPath = child.toFile();
File parent = dir.toFile();
// logger.print(logger.VERBOSE2, logger.PFR, subModule,
// event
// .kind().name() + " filename "+name+" child " + child +
// " parent "+dir + " watchable="+key.watchable());
if (!childPath.getParentFile().getAbsolutePath()
.equals(parent.getAbsolutePath())) {
System.out
.println("ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR");
System.out.println(childPath.getParentFile()
.getAbsoluteFile());
System.out.println(parent.getAbsolutePath());
}
// System.out.println(event.kind().name() +
// " name "+name+" child " + child + " dir "+dir);
// if directory is created, and watching recursively, then
// register it and its sub-directories
if (kind == ENTRY_CREATE) {
// System.out.println("created-" + child);
logFileWriter.println("CREATE:" + child);
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
try {
registerAll(child);
// addToScannedListOnDirRename(child.toFile(),
// false);
} catch (NoSuchFileException ex) {
// logger.print(logger.VERBOSE, logger.PFR,
// moduleName,
// "Received ENTRY_CREATE and NoSuchFileException continuing from here "
// + ex+" for dir "+child);
continue;
}
}
} catch (AccessDeniedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
triggerFullScan();
return;
}
}
File file = child.toFile();
if (kind == ENTRY_CREATE || kind == ENTRY_MODIFY) {
// System.out.println("created/modify-" + child);
logFileWriter.println("CREATE/MODIFY: " + child);
try {
// logger.print(logger.VERBOSE2, logger.PFR,
// subModule, "Adding create event = " + fileInfo);
filesList.add(file.getCanonicalPath());
if (file.isDirectory()) {
}
} catch (Exception e) {
triggerFullScan();
return;
}
} else if (kind == ENTRY_DELETE) {
logFileWriter.println("DELETE: " + child);
deleteDir(file);
}
}
// reset key and remove from set if directory no longer
// accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
triggerFullScan();
String failureCause = e.getMessage();
return;
} catch (Throwable e) {
triggerFullScan();
e.printStackTrace();
return;
}
}
}
private void deleteDir(File file) {
// TODO Auto-generated method stub
}
private void triggerFullScan() {
// TODO Auto-generated method stub
}
/**
* Register the given directory, and all its sub-directories, with the
* WatchService.
*
* @throws PFRScanFailedException
*/
private void registerAll(final Path start) throws Exception {
// register directory and sub-directories
walkFileTree(start);
}
private void walkFileTree(Path start) throws IOException {
int retryCount = 0;
int maxRetry = 5;
String subModule = module + "walkFileTree";
while (true) {
try {
if (start == null) {
return;
}
Files.walkFileTree(start, SFRFileVisitor);
break;
} catch (AccessDeniedException adx) {
retryCount++;
if (retryCount == maxRetry) {
throw adx;
}
File file = start.toFile();
if (file == null || !file.exists()) {
break;
}
waitFor(5000);
continue;
} catch (IOException iex) {
retryCount++;
if (retryCount == maxRetry) {
throw iex;
}
waitFor(5000);
continue;
}
}
}
public static void waitFor(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Process all events for keys queued to the watcher
*/
@Override
public void run() {
Thread.currentThread().setName(uniqueFSName);
try {
DirectoryWatcherCore();
} finally {
freeResources();
}
}
class FilesetSimpleFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
try {
// doScan(file);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
// logger.printStackTrace(logger.PFR,
// "PFRScanFailedException-visitFile", e);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
String subModule = "preVisitDirectory";
try {
register(dir);
// doScan(dir);
return FileVisitResult.CONTINUE;
} catch (NoSuchFileException e) {
return FileVisitResult.SKIP_SUBTREE;
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
}
}
public void startDirectoryRegisterProcess() throws Exception {
// registering all path
String subModule = "-startDirectoryRegisterProcess-";
// logger.print(logger.INFO, logger.PFR, subModule,
// "Initaited registering process");
long startTime = System.currentTimeMillis();
for (Path dir : srcPaths) {
// logger.print(logger.INFO, logger.PFR, subModule,
// "Started registring directory" + dir);
try {
// registering sub directories
File folder = dir.toFile();
if (folder == null) {
continue;
}
File[] listOfFiles = folder.listFiles();
if (listOfFiles == null || listOfFiles.length == 0) {
continue;
}
for (File file : listOfFiles) {
if (file.exists() && file.isDirectory()) {
try {
registerAll(Paths.get(file.getCanonicalPath()));
} catch (NoSuchFileException iox) {
// consume NoSuchFileException exception
}
}
}
} catch (AccessDeniedException e) {
// handleAccessDeniedException(e, true);
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
// handleException(e, true);
}
}
long registrationTime = System.currentTimeMillis() - startTime;
}
public static void testWatchDir(List<Path> dirs) throws Exception {
final DirectoryWatcher dw = new DirectoryWatcher(dirs);
Runnable runner = new Runnable() {
@Override
public void run() {
while (true) {
try {
waitFor(10 * 1000);
System.out.println("Pending file count="
+ filesList.size());
findFilesPresentOnDiskButNotInList();
System.out
.println("----------------------------------");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
new Thread(runner).start();
dw.startDirectoryRegisterProcess();
}
/**
* Checks if the file is present on Disk but not on the list which was
* created by the events that was received by Directory Watcher
*
* @throws Exception
*/
public static void findFilesPresentOnDiskButNotInList() throws Exception {
List<String> missedFiles = new ArrayList<String>();
for (Path src : srcPaths) {
findDiff(src.toFile(), missedFiles);
}
if (missedFiles.size() == 0) {
System.out.println("No files are missed");
} else {
System.out.println("findFilesPresentOnDiskButNotInList");
System.out.println("The files that have been missed are");
for (String filePath : missedFiles) {
System.out.println(filePath);
}
}
System.out.println("###################################");
}
public static void findDiff(File folder, List<String> missedFiles)
throws Exception {
File[] files = folder.listFiles();
if (files != null && files.length > 0) {
for (File child : files) {
if (!filesList.contains(child.getCanonicalPath())) {
missedFiles.add(child.getCanonicalPath());
}
if (child.isDirectory()) {
findDiff(child, missedFiles);
}
}
}
}
public static void main(String[] args) throws Exception {
System.out.println("started");
List<String> pathNames = new ArrayList<String>();
List<Path> dirPaths = new ArrayList<Path>();
// if two arguments are passed to the main function then
// we assume that the first argument represents the directory where the
// files and folders are getting created. And the second argument is for
// the
// path to the log file.
// else we ask the user to enter input through command line
if (args.length < 2) {
getUserInput(pathNames);
} else {
// arg[0] is the folder to be watched
pathNames.add(args[0]);
// arg[1] is the log file that has been created
LOG_FILE_PATH = args[1];
}
// code for log file
System.out.println("The log file is " + LOG_FILE_PATH);
new File(LOG_FILE_PATH).deleteOnExit();
new File(LOG_FILE_PATH).createNewFile();
logFileWriter = new PrintWriter(LOG_FILE_PATH);
for (String path : pathNames) {
dirPaths.add(Paths.get(path));
}
testWatchDir(dirPaths);
System.out.println("ended");
}
private static void getUserInput(List<String> pathNames) {
System.out
.println("please enter the path of directory to be watched for events");
Scanner input = new Scanner(System.in);
if (input.hasNext()) {
pathNames.add(input.nextLine());
}
System.out.println("Please enter the log file path");
if (input.hasNext()) {
LOG_FILE_PATH = input.nextLine();
}
}
}