在smb2网络共享上File.exists()不准确(使用WatchService?)

时间:2015-01-20 13:36:57

标签: java smb watchservice

根据此文档: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。这很有效。

由于

0 个答案:

没有答案