如何通过FileVisitor接口以多线程方式使用Java Files.walkFileTree()?

cunj1qz1  于 2023-01-04  发布在  Java
关注(0)|答案(1)|浏览(174)

需要扫描整个计算机的文件,我想启动一个文件。walkFileTree(startingFolder,FileVisitor)。但是,我发现FileVisitor覆盖方法越来越混乱。如果我只启动一个线程,一切都正常,但当我启动第二个或更多线程时,第一个线程的FileVisitor方法被忽略或使用不正确的文件调用。Files. walkFileTree()是一个静态方法。我为每个线程指定一个新的FileVisitor实现,但是没有用。我发现files.walkFileTree()比其他方法快65%。我怎样才能使它多线程化呢?
节日快乐,谢谢。
彼得·耶克维茨
样本代码:

ArrayList<Path> seeds = new ArrayList<>();   // This is where we are going to start looking 

private void launchTreeWalkers() {
  
 ArrayList<Path> effectivelyFinalPath = this.seeds;   // Physical drives on the computer ie  C:\ D:\ E:\ ...   
  int[] index = new int[1];       //  Effectively Final
  this.twThreads = new Thread[ effectivelyFinalPath.size() ];  // TreeWalkerThreads 
  
  for ( int i=0; i < effectivelyFinalPath.size(); i++ ) {
    index[i] = i; 
    
    this.twThreads[i] = new Thread( new Runnable() { 
                             @Override
                             public void run() {
                               try {
                                tTreeWalker2( effectivelyFinalPath.get( index[0]) );
                              } catch ( Exception ex ) {
                                ex.printStackTrace();
                              }
                             }
                           }
                         );
    
    this.twThreads[i].setDaemon( true );  // So the thread will die when the parent dies.
    this.twThreads[i].setName("Tree Walker");
    this.twThreads[i].start();
  }  
  
  Display.fmt("%1$,d Tree Walker thread%2$s %3$s been started.", box( this.twThreads.length ), Aide.plural(this.twThreads.length), Aide.hasHave( this.twThreads.length ) ); 
}

/** A walkFileTree thread   */
void tTreeWalker( Path startingPath ) throws Exception {
    
  @SuppressWarnings("resource")  // java.lang.UnsupportedOperationException when closing FileSystem  
  FileSystem fileSystem = FileSystems.getDefault();   

  Files.walkFileTree( fileSystem.getPath( startingPath.toString() ), new FileVisitorImpl()); 
}

/** */
public class FileVisitorImpl implements FileVisitor<Path> {
  
  @Override   // Called before a directory visit.
  public FileVisitResult preVisitDirectory( Path directory, BasicFileAttributes attrs ) throws IOException {
    Locate.this.folderCountLA.increment();  // Long Adder

    if ( isMatch( excludeFolders, directory ))
      return FileVisitResult.SKIP_SUBTREE;

    Locate.this.foldersSelectedLA.increment(); 
    return FileVisitResult.CONTINUE;
  }

  @Override   // Called after a directory visit is complete.
  public FileVisitResult postVisitDirectory( Path dir, IOException exc ) throws IOException {
    return FileVisitResult.CONTINUE;
  }

  @Override    // This method is called for each file visited. The basic attributes of the files are also available.
  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
    Locate.this.fileCountLA.increment();

    if ( ! isMatch( excludeFiles, file  ) ) {
      FileOfInterest foi = new FileOfInterest( file );
      
      try { 
        if (( probZips ) && ( foi.isCompressedFile() )) { 
          foundFilesQ.put( foi );
          //TODO  Zip handler goes here 
          
        } else if ( isMatch( selectFiles, file  ) ) {   
          Locate.this.filesSelectedLA.increment();
          foundFilesQ.put( foi );   // Blocking if the Q is full.    
        }

      } catch ( InterruptedException ex ) { // We do not expect this to ever happen.
        ex.printStackTrace();
      }
    }
    return FileVisitResult.CONTINUE;
  }

  @Override   // If the file visit fails for any reason, the visitFileFailed method is called.
  public FileVisitResult visitFileFailed( Path file, IOException exc) throws IOException {

    if ( ! isMatch( knownFailures, file ) ) { // Ignore known failures 
      String msg = exc.toString();

      if ( msg.contains( "java.nio.file.AccessDeniedException" )) {
        Locate.this.accessDeniedLA.increment();

        if ( showAccessDenied ) 
          Display.fmt("visitFileFailed  %s", exc.toString() );
      } else {
        Locate.this.failuresLA.increment();
        Display.fmt("visitFileFailed  %s", exc.toString() );        
      }
    }  

    return FileVisitResult.CONTINUE;
  }
}  // End of FileVisitorImpl
kupeojn6

kupeojn61#

问题解决了。在试图通过创建Effectively Final变量作为数组来欺骗java以用于创建runnable时,我感到很痛苦。当我在测试用例中创建4个线程时,所有4个线程都在同一个驱动器上运行,最后一个进入。它们没有按顺序使用,当时,我在其中创建了runnable。我通过让线程访问AtomicInteger来索引包含驱动器的数组来解决这个问题。我还在线程中创建了FileVisitorImpl。谢谢并祝新年快乐。Peter Jerkewitz

相关问题