Java view directory is giving me wrong file path for events

I am using JDK7 "Watch Change Directory". But I found that sometimes it gives me the wrong file path for a specific event in the file. Even if the filename is correct. I faced this issue in fedora and ubuntu Someone is facing the same problem.

Steps to reproduce:

  • Download and extract the zip from https://dl.dropboxusercontent.com/u/39897681/code/fileOperation.zip to generate files. Please configure it to generate files by reading the README.txt

  • Run Sample Java code with an empty source folder and a file [for log targets] as input. And wait a while

  • Run Main.py from the loaded content, setting it up so it will generate files and folders.

  • The java program will display a list of files present on disk, but not in the list [list generated from files retrieved from browsing directory]

Originally java output: ie no events lost

Program exit Expected number of files = 2398 No skipped files.

#

But in the end, we lose some events for files or get the wrong path after a while

Number of files expected = 4552

findFilesPresentOnDiskButNotInList

Skipped files / data / home / developer / test / folder _0.689628351684 / folder_0.0451760705904 / folder_0.000447662431096 / folder_0.264689686702 / folder_0.849536150754 / folder_0.216092330336 / folder_0.6777925641024 / folder720

#

Here folder_0.0451760705904 is created with an absolute path / data / home / developer / test / folder _0.689628351684 / folder_0.0451760705904, but in the log file it prints a different path for that folder.

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();
}

}

}

      

+3


source to share





All Articles