Feeding Files.walkFileTree() with a root folder (e.g. "T:/") produces the error:
java.nio.file.AccessDeniedException: T:\System Volume Information
at java.nio.file.Files.newDirectoryStream(Files.java:457)
at java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:300)
at java.nio.file.FileTreeWalker.next(FileTreeWalker.java:372)
at java.nio.file.Files.walkFileTree(Files.java:2706)
at java.nio.file.Files.walkFileTree(Files.java:2742)
The callback preVisitDirectory() is not called:
@Override
public FileVisitResult preVisitDirectory( Path aFile,
BasicFileAttributes aAttrs )
throws IOException
{
if ( "System Volume Information".equals( ( aFile.getFileName() ) ) )
{
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
Neither the apache FileUtils.deleteDirectory( new File( "T:/" ) ) can handle this situation.
I came across to write following code:
public static void deleteDirRecursive( Path aDir ) throws IOException
{
if ( aDir == null )
{
throw new IllegalArgumentException( "aDir must not be null" );
}
if ( Files.notExists( aDir ) )
{
return;
}
if ( aDir.isAbsolute() && aDir.getRoot().equals( aDir ) )
{
myLog.debug( "Given path object is a root. On windows we cannot delete 'System Volume Information' folder!" );
// -> iterate over the entries in root and skip "System Volume information"
Arrays.asList( aDir.toFile().listFiles(
new FilenameFilter()
{
@Override
public boolean accept( File aDirectory, String aName )
{
return !"System Volume Information".equals( aName );
}
} )
).forEach
( dir ->
{
try
{
if ( dir.isDirectory() )
{
deleteDirRecursive( Paths.get( dir.getAbsolutePath() ) );
}
else
{
Files.delete( Paths.get( dir.getAbsolutePath() ) );
}
}
catch ( Exception e )
{
throw new IllegalArgumentException( "", e );
}
}
);
return;
}
if ( !Files.isDirectory( aDir ) )
{
throw new IllegalArgumentException( "given aDir is not a directory" );
}
Files.walkFileTree( aDir, new SimpleFileVisitor<Path>()
{
@Override
public FileVisitResult visitFile( Path file,
BasicFileAttributes attrs )
throws IOException
{
Files.delete( file );
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory( Path dir, IOException exc )
throws IOException
{
Files.delete( dir );
return FileVisitResult.CONTINUE;
}
} );
}
Notice that the biggest part of this code is only the special handling of "System Volume Information" (the whole "if ( aDir.isAbsolute() ...."). Very ugly.
Is there a more elegant solution to exclude this folder from a tree walk?
I know it's late, but I had this issue too; I'll document it there.
FileVisitor
has a method called FileVisitResult visitFileFailed(T file, IOException exc)
SimpleFileVisitor
implements it by re-throwing the exception.
Just override that method in your own implementation, handling the exception the way you deem necessary.