java7:Files.walkFileTree() 和 "System Volume information" 在 windows 系统上
java7: Files.walkFileTree() and "System Volume information" on windows systems
向 Files.walkFileTree() 提供根文件夹(例如 "T:/")会产生错误:
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)
未调用回调 preVisitDirectory():
@Override
public FileVisitResult preVisitDirectory( Path aFile,
BasicFileAttributes aAttrs )
throws IOException
{
if ( "System Volume Information".equals( ( aFile.getFileName() ) ) )
{
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
apache FileUtils.deleteDirectory( new File( "T:/" ) ) 都无法处理这种情况。
我无意中写了下面的代码:
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;
}
} );
}
注意这段代码的最大部分只是对"System Volume Information"(整个"if ( aDir.isAbsolute() ....")的特殊处理。很丑
是否有更优雅的解决方案将此文件夹排除在树遍历之外?
这是我的一个名为 java7-fs-more:
的软件包的解决方案
final Path path = Paths.get("T:");
MoreFiles.deleteRecursive(path, RecursionMode.KEEP_GOING);
这将继续删除文件和目录,即使它在某一时刻失败了。
在 return,您将获得(在您的情况下)RecursiveDeletionException
;删除期间引发的所有异常都是此异常的 "attached"(参见 Throwable#getSuppressed()
)。
另一种解决方案(不保证)是检查路径的 dos:system
属性;如果为真,那么您可能希望避免删除它。
请注意,不幸的是,在 FileVisitor
中,您只有在访问文件时才能访问 BasicFileAttributes
;为了检查 dos:system
你想做的就是这样做:
Files.readAttributes(path, DosFileAttributes.class).isSystem()
另一个解决方案,因为你似乎在使用 Java 8,是使用 Files.walk()
并过滤条目;不幸的是,读取属性会引发 IOException,所以,在这里,我再次使用我的另一个包,throwing-lambdas,以某种方式解决它:
final ThrowingPredicate<Path> notSystem
= path -> !Files.readAttributes(path, DosFileAttributes.class).isSystem();
final ThrowingConsumer<Path> remove = Files::delete;
try (
final Stream<Path> stream = Files.walk(Paths.get("T:"));
) {
stream.filter(notSystem.orReturnTrue()).forEach(remove.orDoNothing());
}
我知道已经晚了,但我也遇到了这个问题;我会在那里记录下来。
FileVisitor
有一个名为 FileVisitResult visitFileFailed(T file, IOException exc)
的方法
SimpleFileVisitor
通过重新抛出异常来实现它。
只需在您自己的实现中覆盖该方法,以您认为必要的方式处理异常。
向 Files.walkFileTree() 提供根文件夹(例如 "T:/")会产生错误:
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)
未调用回调 preVisitDirectory():
@Override
public FileVisitResult preVisitDirectory( Path aFile,
BasicFileAttributes aAttrs )
throws IOException
{
if ( "System Volume Information".equals( ( aFile.getFileName() ) ) )
{
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
apache FileUtils.deleteDirectory( new File( "T:/" ) ) 都无法处理这种情况。
我无意中写了下面的代码:
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;
}
} );
}
注意这段代码的最大部分只是对"System Volume Information"(整个"if ( aDir.isAbsolute() ....")的特殊处理。很丑
是否有更优雅的解决方案将此文件夹排除在树遍历之外?
这是我的一个名为 java7-fs-more:
的软件包的解决方案final Path path = Paths.get("T:");
MoreFiles.deleteRecursive(path, RecursionMode.KEEP_GOING);
这将继续删除文件和目录,即使它在某一时刻失败了。
在 return,您将获得(在您的情况下)RecursiveDeletionException
;删除期间引发的所有异常都是此异常的 "attached"(参见 Throwable#getSuppressed()
)。
另一种解决方案(不保证)是检查路径的 dos:system
属性;如果为真,那么您可能希望避免删除它。
请注意,不幸的是,在 FileVisitor
中,您只有在访问文件时才能访问 BasicFileAttributes
;为了检查 dos:system
你想做的就是这样做:
Files.readAttributes(path, DosFileAttributes.class).isSystem()
另一个解决方案,因为你似乎在使用 Java 8,是使用 Files.walk()
并过滤条目;不幸的是,读取属性会引发 IOException,所以,在这里,我再次使用我的另一个包,throwing-lambdas,以某种方式解决它:
final ThrowingPredicate<Path> notSystem
= path -> !Files.readAttributes(path, DosFileAttributes.class).isSystem();
final ThrowingConsumer<Path> remove = Files::delete;
try (
final Stream<Path> stream = Files.walk(Paths.get("T:"));
) {
stream.filter(notSystem.orReturnTrue()).forEach(remove.orDoNothing());
}
我知道已经晚了,但我也遇到了这个问题;我会在那里记录下来。
FileVisitor
有一个名为 FileVisitResult visitFileFailed(T file, IOException exc)
SimpleFileVisitor
通过重新抛出异常来实现它。
只需在您自己的实现中覆盖该方法,以您认为必要的方式处理异常。