5

根据此文档:http : //technet.microsoft.com/en-us/library/ff686200%28v=ws.10%29.aspx File.exists() 在 smb2 网络共享上不准确。我无法更改任何寄存器设置,所以我想处理它。根据文档,有一个 API 可以从文件系统获取通知。我假设 WatchService 是这个 API 的 Java 实现。我对么?

我从 jdk 示例中的 WatchDir 示例开始,并对其进行了一些剥离。我只需要知道何时创建和删除文件(我不关心文件修改)。为了进行测试,我在触发新事件时添加了新的 File.exists()。我还启动了一个单独的线程来测试文件是否存在。当我不启动这个单独的线程时,文件存在立即返回 true。当额外的线程启动时,它不再准确。我需要一个更准确的 file.exists 检查整个应用程序和所有正在运行的线程。

为了测试,我使用了 2 台 Windows 7 电脑(运行 java 7)(默认启用 smb2)。工作目录必须在远程 pc 上,并且文件 test.txt 必须在远程 pc 上创建(或从另一个文件夹复制)(不使用网络驱动器,但在 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 毫秒后)。

有任何想法吗?

[编辑]

我也试过这个:

 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(file)。这将引发 FileNotFoundExeption,而此 fileExists() 方法返回 true。现在我等到 new File().exists() 在打开 FileInputStream 之前返回 true。这行得通。

谢谢

4

0 回答 0