如何在Java中递归列出目录下的所有文件?框架是否提供任何实用工具?
我看到了很多hacky实现,但都不是来自框架或nio。
Java 8提供了一个很好的流来处理树中的所有文件。
try (Stream<Path> stream = Files.walk(Paths.get(path))) {
stream.filter(Files::isRegularFile)
.forEach(System.out::println);
}
这提供了一种自然的遍历文件的方式。由于它是一个流,您可以对结果进行所有漂亮的流操作,例如限制、分组、映射、提前退出等。
更新:我可能需要指出,还有一个Files.find方法,它接受一个BiPredicate,如果需要检查文件属性,则可能更有效。
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
请注意,虽然JavaDoc暗示此方法可能比Files.walk更有效率,但实际上它们几乎相同。只有在您同时检索文件属性时才能观察到性能差异。最终,如果您需要根据属性进行过滤,请使用Files.find,否则请使用Files.walk,主要是因为有很多重载,更加方便。
测试:按照要求提供了许多答案的性能比较。请查看Github项目中包含的结果和测试用例。
Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
。我该如何纠正它? - KachnaFileUtils有iterateFiles
和listFiles
方法。请尝试使用它们。(来自commons-io)
编辑:您可以在这里检查不同方法的基准测试。看起来commons-io方法很慢,所以从这里选择一些更快的方法(如果有必要)。
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
。这里的dir
是指向基础目录的一个File对象。 - andronikuslistFilesAndDirs()
,因为listFiles()
不会返回空文件夹。 - schnattererFileUtils.listFiles(dir, true, true)
。使用 FileUtils.listFiles(dir, null, true)
会抛出异常,而 FileUtils.listFiles(dir, true, null)
则会列出所有文件而不会查看子目录。 - ocramot// 准备运行
import java.io.File;
public class Filewalker {
public void walk( String path ) {
File root = new File( path );
File[] list = root.listFiles();
if (list == null) return;
for ( File f : list ) {
if ( f.isDirectory() ) {
walk( f.getAbsolutePath() );
System.out.println( "Dir:" + f.getAbsoluteFile() );
}
else {
System.out.println( "File:" + f.getAbsoluteFile() );
}
}
}
public static void main(String[] args) {
Filewalker fw = new Filewalker();
fw.walk("c:\\" );
}
}
-> .
。 - Brett Ryan"/"
,"./"
或"../"
分别表示根目录、当前工作目录和父目录。 - Moses KiratheJava 7 will have已经拥有Files.walkFileTree方法:
如果您提供起始点和文件访问器,它将在文件树中遍历文件时调用文件访问器上的各种方法。我们期望人们在开发递归复制、递归移动、递归删除或对每个文件设置权限或执行其他操作的递归操作时使用此方法。
现在已经有一整个Oracle关于这个问题的教程了。
不需要外部库。
返回一个Collection,所以在调用后你可以做任何你想做的事情。
public static Collection<File> listFileTree(File dir) {
Set<File> fileTree = new HashSet<File>();
if(dir==null||dir.listFiles()==null){
return fileTree;
}
for (File entry : dir.listFiles()) {
if (entry.isFile()) fileTree.add(entry);
else fileTree.addAll(listFileTree(entry));
}
return fileTree;
}
我会选择类似以下的做法:
public void list(File file) {
System.out.println(file.getName());
File[] children = file.listFiles();
for (File child : children) {
list(child);
}
}
System.out.println只是用来指示对文件执行某些操作。没有必要区分文件和目录,因为普通文件将简单地没有子项。
listFiles()
的文档,“如果这个抽象路径名不表示一个目录,那么该方法将返回null
。” - hfspublic static Collection listFileTree(File dir) {
if (null == dir || !dir.isDirectory()) {
return Collections.emptyList();
}
final Set fileTree = new HashSet();
for (File entry : Objects.requireNonNull(dir.listFiles())) {
if (entry.isFile()) {
fileTree.add(entry);
} else {
fileTree.addAll(listFileTree(entry));
}
}
return fileTree;
}
- Ben对于这种简单的遍历,我更喜欢使用队列而不是递归:
List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
for (File f : dirs.poll().listFiles()) {
if (f.isDirectory()) {
dirs.add(f);
} else if (f.isFile()) {
allFiles.add(f);
}
}
}
只需要使用简单的递归自己编写:
public List<File> addFiles(List<File> files, File dir)
{
if (files == null)
files = new LinkedList<File>();
if (!dir.isDirectory())
{
files.add(dir);
return files;
}
for (File file : dir.listFiles())
addFiles(files, file);
return files;
}
Java 7 中您可以使用以下类:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class MyFileIterator extends SimpleFileVisitor<Path>
{
public MyFileIterator(String path) throws Exception
{
Files.walkFileTree(Paths.get(path), this);
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attributes) throws IOException
{
System.out.println("File: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attributes) throws IOException
{
System.out.println("Dir: " + dir);
return FileVisitResult.CONTINUE;
}
}
这段代码已经可以运行
public static void main(String... args) {
File[] files = new File("D:/").listFiles();
if (files != null)
getFiles(files);
}
public static void getFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
getFiles(file.listFiles());
} else {
System.out.println("File: " + file);
}
}
}