![](/img/trans.png)
[英]Moving not empty directory recursively using Java NIO.2 FileVisitor and Files.walkFileTree(…)
[英]How can Java Files.walkFileTree() be used in a multiThread fashion using the FileVisitor interface?
需要扫描整个计算机的文件,我想在计算机上的每个物理驱动器上启动 Files.walkFileTree(startingFolder, FileVisitor)。 但是,我发现 FileVisitor 覆盖方法越来越混乱。 如果我只启动一个线程,一切正常,但是当我启动第二个或更多线程时,第一个线程的 FileVisitor 方法将被忽略或使用不正确的文件进行调用。 Files.walkFileTree() 是一个 static 方法。 我为每个线程指定了一个新的 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
问题解决了。 试图通过创建 Effectively Final 变量作为 arrays 来愚弄 java 以用于创建 runnable,这让我很苦恼。 当我在我的测试用例中创建 4 个线程时,所有 4 个线程都在同一个驱动器上运行,最后一个进入。 它们没有按照我创建可运行程序的顺序使用。 我通过让线程访问 AtomicInteger 来索引包含驱动器的数组来解决这个问题。 我还在线程中创建了 FileVisitorImpl。 谢谢,新年快乐。 彼得杰科维茨
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.