在 Java 中递归列出文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2056221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Recursively list files in Java
提问by Quintin Par
采纳答案by Brett Ryan
Java 8 provides a nice stream to process all files in a tree.
Java 8 提供了一个很好的流来处理树中的所有文件。
Files.walk(Paths.get(path))
.filter(Files::isRegularFile)
.forEach(System.out::println);
This provides a natural way to traverse files. Since it's a stream you can do all nice stream operations on the result such as limit, grouping, mapping, exit early etc.
这提供了一种自然的方式来遍历文件。由于它是一个流,您可以对结果执行所有不错的流操作,例如限制、分组、映射、提前退出等。
UPDATE: I might point out there is also Files.findwhich takes a BiPredicatethat could be more efficient if you need to check file attributes.
更新:我可能会指出还有Files.find,它采用BiPredicate,如果您需要检查文件属性,它可能会更有效。
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
Note that while the JavaDoc eludes that this method could be more efficient than Files.walkit is effectively identical, the difference in performance can be observed if you are also retrieving file attributes within your filter. In the end, if you need to filter on attributes use Files.find, otherwise use Files.walk, mostly because there are overloads and it's more convenient.
请注意,虽然 JavaDoc 没有说明此方法可能比Files.walk更有效,但实际上是相同的,如果您还在过滤器中检索文件属性,则可以观察到性能差异。最后,如果你需要过滤属性使用Files.find,否则使用Files.walk,主要是因为有重载而且更方便。
TESTS: As requested I've provided a performance comparison of many of the answers. Check out the Github project which contains results and a test case.
回答by Micha? Niklas
I think this should do the work:
我认为这应该可以完成工作:
File dir = new File(dirname);
String[] files = dir.list();
This way you have files and dirs. Now use recursion and do the same for dirs (File
class has isDirectory()
method).
这样你就有了文件和目录。现在使用递归并对 dirs 执行相同的操作(File
类具有isDirectory()
方法)。
回答by Bozho
FileUtilshave iterateFiles
and listFiles
methods. Give them a try. (from commons-io)
FileUtils有iterateFiles
和listFiles
方法。给他们一个尝试。(来自commons-io)
Edit: You can check herefor a benchmark of different approaches. It seems that the commons-io approach is slow, so pick some of the faster ones from here(if it matters)
编辑:您可以在此处查看不同方法的基准。似乎 commons-io 方法很慢,所以从这里选择一些更快的方法(如果重要的话)
回答by pstanton
just write it yourself using simple recursion:
只需使用简单的递归自己编写:
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;
}
回答by Stefan Schmidt
I would go with something like:
我会选择类似的东西:
public void list(File file) {
System.out.println(file.getName());
File[] children = file.listFiles();
for (File child : children) {
list(child);
}
}
The System.out.println is just there to indicate to do something with the file. there is no need to differentiate between files and directories, since a normal file will simply have zero children.
System.out.println 只是用于指示对文件执行某些操作。不需要区分文件和目录,因为普通文件只会有零个子文件。
回答by stacker
// Ready to run
// 准备运行
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:\" );
}
}
回答by yawn
Java 7 will havehas Files.walkFileTree:
Java 7的将有Files.walkFileTree:
If you provide a starting point and a file visitor, it will invoke various methods on the file visitor as it walks through the file in the file tree. We expect people to use this if they are developing a recursive copy, a recursive move, a recursive delete, or a recursive operation that sets permissions or performs another operation on each of the files.
如果您提供起点和文件访问者,它将在文件访问者遍历文件树中的文件时调用文件访问者的各种方法。我们希望人们在开发递归复制、递归移动、递归删除或设置权限或对每个文件执行其他操作的递归操作时使用它。
There is now an entire Oracle tutorial on this question.
回答by sateesh
Apart from the recursive traversal one can use a Visitor based approach as well.
除了递归遍历之外,还可以使用基于访问者的方法。
Below code is uses Visitor based approach for the traversal.It is expected that the input to the program is the root directory to traverse.
下面的代码是使用基于访问者的方法进行遍历。预计程序的输入是要遍历的根目录。
public interface Visitor {
void visit(DirElement d);
void visit(FileElement f);
}
public abstract class Element {
protected File rootPath;
abstract void accept(Visitor v);
@Override
public String toString() {
return rootPath.getAbsolutePath();
}
}
public class FileElement extends Element {
FileElement(final String path) {
rootPath = new File(path);
}
@Override
void accept(final Visitor v) {
v.visit(this);
}
}
public class DirElement extends Element implements Iterable<Element> {
private final List<Element> elemList;
DirElement(final String path) {
elemList = new ArrayList<Element>();
rootPath = new File(path);
for (File f : rootPath.listFiles()) {
if (f.isDirectory()) {
elemList.add(new DirElement(f.getAbsolutePath()));
} else if (f.isFile()) {
elemList.add(new FileElement(f.getAbsolutePath()));
}
}
}
@Override
void accept(final Visitor v) {
v.visit(this);
}
public Iterator<Element> iterator() {
return elemList.iterator();
}
}
public class ElementWalker {
private final String rootDir;
ElementWalker(final String dir) {
rootDir = dir;
}
private void traverse() {
Element d = new DirElement(rootDir);
d.accept(new Walker());
}
public static void main(final String[] args) {
ElementWalker t = new ElementWalker("C:\temp");
t.traverse();
}
private class Walker implements Visitor {
public void visit(final DirElement d) {
System.out.println(d);
for(Element e:d) {
e.accept(this);
}
}
public void visit(final FileElement f) {
System.out.println(f);
}
}
}
回答by benroth
I prefer using a queue over recursion for this kind of simple traversion:
对于这种简单的遍历,我更喜欢使用队列而不是递归:
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);
}
}
}
回答by Petrucio
No external libraries needed.
Returns a Collection so you can do whatever you want with it after the call.
不需要外部库。
返回一个集合,这样你就可以在调用后对它做任何你想做的事情。
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;
}
回答by bobah
Non-recursive BFS with a single list (particular example is searching for *.eml files):
具有单个列表的非递归 BFS(特定示例是搜索 *.eml 文件):
final FileFilter filter = new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory() || file.getName().endsWith(".eml");
}
};
// BFS recursive search
List<File> queue = new LinkedList<File>();
queue.addAll(Arrays.asList(dir.listFiles(filter)));
for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) {
File file = itr.next();
if (file.isDirectory()) {
itr.remove();
for (File f: file.listFiles(filter)) itr.add(f);
}
}