When a directory monitored by a WatchService gets deleted, its parent directory does not immediately reflect the deletion in its File's listFiles method and cannot be deleted. Until the entire service is explicitly stopped the consequences for the parent appear to be:
To demonstrate, this test code:
import java.io.*;
import java.nio.file.*;
class DirectoryTester {
static WatchService watcher;
static {
try{watcher = FileSystems.getDefault().newWatchService();}
catch (IOException e) {e.printStackTrace();}
}
public static void main(String[] args) throws IOException {
String SEPARATE = System.getProperty("file.separator");
String testDirName = System.getProperty("user.dir") + SEPARATE + "testDir";
String subDirName = testDirName + SEPARATE + "subDir";
String fileName = subDirName + SEPARATE +"aFile";
create(fileName);
Paths.get(subDirName).register(watcher, StandardWatchEventKinds.ENTRY_DELETE);
delete(new File(testDirName));
}
static void create(String nameOfFile) throws IOException {
new File(nameOfFile).getParentFile().mkdirs();
Files.createFile(Paths.get(nameOfFile));
System.out.println("Created " + nameOfFile);
}
static void delete(File toDelete) throws IOException {
if (toDelete.isDirectory())
for (File c : toDelete.listFiles())
delete(c);
int numContainedFiles = toDelete.listFiles() != null ? toDelete.listFiles().length : 0;
if (!toDelete.delete()) {
System.out.println("Failed to delete " + toDelete + " containing " + numContainedFiles);
}
else {
System.out.println("Deleted " + toDelete + " containing " + numContainedFiles);
}
}
}
gives the following output on windows, which corresponds with testDir
not being deleted on the filesystem.
Created C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile containing 0
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir containing 0
Failed to delete C:\Dropbox\CodeSpace\JavaTestbed\src\testDir containing 1
If I put a breakpoint after the subDir
deletion I can see that it has actually been deleted on the filesystem. Resuming from the breakpoint causes the last deletion to suceed, suggesting that this might be an issue with the visibility of changes made by the watch service thread. Does anyone know what is going on here, and if it is a bug? What I am actually trying to do is to delete directories that are monitored without stopping the monitoring on other directories, given that there does not appear to be an unregister path method provided by the API what are other standard Java ways of accomplishing this?
public class FileSystemWatcher extends Object. Watches specific directories for file changes.
A watch service that watches registered objects for changes and events. For example a file manager may use a watch service to monitor a directory for changes so that it can update its display of the list of files when files are created or deleted.
The “\$Extend\$Deleted” directory unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse.
possibly related:
http://bugs.sun.com/view_bug.do?bug_id=6972833
The WatchService has an open handle to each watched directory. If a a watch directory is deleted then the WatchService closes the handle so that the directory entry can be removed from the parent directory. A problem arises for utilities and application that expect to be able to delete the parent directory immediately as it can take a few milliseconds for the watch service to get the notificationa and close the handle. If during that time that the tool attempts to delete the parent directory then it will fail. We don't have a solution to this issue at this time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With