According to this document: http://technet.microsoft.com/en-us/library/ff686200%28v=ws.10%29.aspx File.exists () is not exact on the smb2 share. I cannot change any registry settings, so I want to deal with this. According to the document, there is an API for receiving notifications from the file system. I suggested that WatchService is a Java implementation of this API. Am I right?
I started with the WatchDir example from jdk samples and deprived it a bit. I only need to know when the file is created and deleted (I do not care about file changes). For testing, I added a new File.exists () when a new event was fired. I also start a split stream, which also checks for the existence of the file. When I do not start this dedicated thread, the file exists, immediately returns true. When an extra thread starts, it is not accurate. I need a more accurate file.exists to check the entire application and all running threads.
For testing, I used 2 Windows 7 pc (java 7 works) (with smb2 enabled, which by default). The working directory must be located on the remote PC, and the test.txt file must be created (or copied from another folder) on the remote computer (not using a network drive, but the computer itself).
Here is my test code:
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.OVERFLOW; import java.io.File; import java.io.IOException; import java.nio.file.ClosedWatchServiceException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; public class WatchDir { private final WatchService _watcher; private final String _dir; public WatchDir( String dir ) throws IOException { _dir = dir; _watcher = FileSystems.getDefault().newWatchService(); Paths.get( dir ).register( _watcher, ENTRY_CREATE, ENTRY_DELETE ); System.out.println( "watch registered for dir: " + dir ); } public void run() { try { while ( true ) { WatchKey key = _watcher.take(); for ( WatchEvent<?> event : key.pollEvents() ) { WatchEvent.Kind<?> kind = event.kind(); if ( kind == OVERFLOW ) continue; @SuppressWarnings( "unchecked" ) WatchEvent<Path> ev = (WatchEvent<Path>)event; Path fileName = ev.context(); System.out.println( "WatchDir event: " + kind.name() + ": " + fileName ); if ( kind == ENTRY_CREATE ) { String realPath = _dir + fileName; System.out.println( "WatchDir: " + realPath + " exists == " + new File( realPath ).exists() ); } } key.reset(); } } catch ( ClosedWatchServiceException x ) { return; } catch ( InterruptedException ex ) { return; } } public static void main( String[] args ) { Thread t = new Thread( new Runnable() { @Override public void run() { try { while ( true ) { String filename = "subdir\\test.txt"; boolean fileExists = new File( filename ).exists(); System.err.println( "FileExistsThread: " + filename + " == " + fileExists ); Thread.sleep( 300 ); } } catch ( InterruptedException e ) { e.printStackTrace(); return; } } } ); t.start(); try { new WatchDir( "subdir\\" ).run(); } catch ( IOException e ) { e.printStackTrace(); } } }
The result for my test case is this:
1. FileExistsThread: subdir\test.txt == false 2. watch registered for dir: subdir\ 3. FileExistsThread: subdir\test.txt == false 4. FileExistsThread: subdir\test.txt == false 5. FileExistsThread: subdir\test.txt == false 6. FileExistsThread: subdir\test.txt == false 7. FileExistsThread: subdir\test.txt == false 8. FileExistsThread: subdir\test.txt == false 9. WatchDir event: ENTRY_CREATE: test.txt 10. WatchDir: subdir\test.txt exists == false 11. FileExistsThread: subdir\test.txt == false 12. FileExistsThread: subdir\test.txt == false 13. FileExistsThread: subdir\test.txt == false 14. FileExistsThread: subdir\test.txt == false 15. FileExistsThread: subdir\test.txt == false 16. FileExistsThread: subdir\test.txt == false 17. FileExistsThread: subdir\test.txt == false 18. FileExistsThread: subdir\test.txt == false 19. FileExistsThread: subdir\test.txt == false 20. FileExistsThread: subdir\test.txt == true 21. FileExistsThread: subdir\test.txt == true 22. FileExistsThread: subdir\test.txt == true 23. FileExistsThread: subdir\test.txt == true
As you can see, the test.txt file is created on line 9. The watchService service notified it. But in reality, the application cannot use it: FileExistsThread saw it in line 20 (at least 10 x 300 ms later).
Any idea?
[edit]
I also tried this:
public synchronized static boolean fileExists( final String fileName ) { File f = new File( fileName ); String fullFileName = f.getAbsolutePath(); final String shortfileName = f.getName(); File dir = new File( fullFileName ).getParentFile(); if ( dir == null ) return false; String[] list = dir.list( new FilenameFilter() { @Override public boolean accept( File dir, String name ) { return name.equalsIgnoreCase( shortfileName ); } } ); if ( list == null ) return false; return list.length == 1; }
This method returns true when I expected. But I still can not use the file after it. I really want to open a new FileInputStream (file). This calls FileNotFoundExeption, whereas this fileExists () method returns true. Now I am waiting for the new File (). Exists () returns true before opening FileInputStream. It works.
thanks