根据此文档:http://technet.microsoft.com/en-us/library/ff686200%28v=ws.10%29.aspx File.exists()在smb2网络共享上不准确。我无法更改任何寄存器设置,所以我想处理它。根据该文档,有一个API来从文件系统获取通知。我假设WatchService是此API的Java实现。我是对的吗?
我从jdk示例开始使用WatchDir示例并将其剥离了一下。我只需要知道何时创建和删除文件(我不关心文件修改)。为了测试,我在触发新事件时添加了新的File.exists()。我也启动一个单独的Thread来测试文件的存在。当我不启动这个分离的线程时,文件存在立即返回true。当额外的线程启动时,它不再准确。我需要一个更准确的文件。检查整个应用程序和所有正在运行的线程。
为了测试,我使用了2台Windows 7 pc(运行java 7)(启用了smb2,这是默认设置)。工作目录必须位于远程PC上,并且必须在远程PC上创建(或从其他文件夹中复制)文件test.txt(不使用网络驱动器,而是在PC上)。
这是我的测试代码:
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();
}
}
}
我的测试用例的输出是:
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
正如您所看到的,文件test.txt是在第9行创建的.watchService已通知它。但实际上应用程序无法使用它:FileExistsThread已在第20行看到它(至少10 x 300 ms后)。
任何想法?
[编辑]
我也试过这个:
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;
}
此方法在我预期时返回true。但我仍然无法使用该文件。我实际上想要打开一个新的FileInputStream(文件)。这将抛出FileNotFoundExeption,而此fileExists()方法返回true。现在我等待直到新的File()。exists()在打开FileInputStream之前返回true。这很有效。
由于