用Javarecursion列出文件
我如何recursion列出在Java目录下的所有文件? 框架是否提供任何实用工具?
我看到很多hacky的实现。 但是没有一个来自框架或者nio
iterateFiles
有iterateFiles
和iterateFiles
方法。 给他们一个尝试。 (来自commons-io )
编辑:你可以在这里检查一个不同的方法的基准。 看来commons-io方法很慢,所以从这里select一些更快的(如果有的话)
Java 8提供了一个很好的stream来处理树中的所有文件。
Files.walk(Paths.get(path)) .filter(Files::isRegularFile) .forEach(System.out::println);
这提供了一种自然的方式来遍历文件。 由于它是一个stream,你可以对结果进行所有漂亮的stream操作,比如限制,分组,映射,退出等等。
更新 :我可能会指出,也有Files.find需要BiPredicate ,如果您需要检查文件属性可以更有效。
Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile()) .forEach(System.out::println);
请注意,虽然JavaDoc避免了这种方法可能比Files.walk更有效, 但是它是完全相同的,如果您还要在filter中检索文件属性,则可以观察到性能的差异。 最后,如果你需要过滤属性,使用Files.find ,否则使用Files.walk ,主要是因为有重载,它更方便。
testing :根据要求,我提供了许多答案的性能比较。 查看包含结果和testing用例的Github项目 。
//准备运行
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:\\" ); } }
Java 7 将具有Files.walkFileTree :
如果你提供了一个起点和一个文件访问者,它将在文件访问者遍历文件树中的文件时调用各种方法。 我们希望人们在开发recursion副本,recursion移动,recursion删除或设置权限或对每个文件执行另一个操作的recursion操作时使用它。
现在有关这个问题的完整的Oracle教程 。
不需要外部库。
返回一个集合,所以你可以做任何你想要的,在它之后。
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只是在那里表明做文件的事情。 没有必要区分文件和目录,因为普通的文件只会有零个孩子。
只需使用简单的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; }
我更喜欢使用这种简单的traversionrecursion队列:
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); } } }
在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; } }
我认为这应该做的工作:
File dir = new File(dirname); String[] files = dir.list();
这样你有文件和目录。 现在使用recursion,并为目录做相同的事情( File
类有isDirectory()
方法)。
在Java 8中,我们现在可以使用Files实用工具来遍历文件树。 很简单。
Files.walk(root.toPath()) .filter(path -> !Files.isDirectory(path)) .forEach(path -> System.out.println(path));
除了recursion遍历之外,还可以使用基于访问者的方法。
下面的代码是使用基于访问的方法进行遍历。预计程序的input是遍历的根目录。
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); } } }
您可以使用下面的代码recursion地获取特定文件夹或目录的文件列表。
public static void main(String args[]) { recusiveList("D:"); } public static void recursiveList(String path) { File f = new File(path); File[] fl = f.listFiles(); for (int i = 0; i < fl.length; i++) { if (fl[i].isDirectory() && !fl[i].isHidden()) { System.out.println(fl[i].getAbsolutePath()); recusiveList(fl[i].getAbsolutePath()); } else { System.out.println(fl[i].getName()); } } }
带有单个列表的非recursionBFS(特定示例是search* .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); } }
我的版本(当然,我可以使用内置的Java 8 ;-)):
public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) { ArrayList<File> collected = new ArrayList<>(); walk(rootDir, predicate, collected); return collected; } private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) { Stream.of(listOnlyWhenDirectory(dir)) .forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction))); } private static File[] listOnlyWhenDirectory(File dir) { return dir.isDirectory() ? dir.listFiles() : new File[]{}; } private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) { if (filterFunction.test(toAdd)) { files.add(toAdd); } return files; }
示例输出目录中的.csv文件recursionsearch使用java.nio中Files.find()的子目录:
String path = "C:/Daten/ibiss/ferret/"; logger.debug("Path:" + path); try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) { List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList()); for (String t : someThingNew) { t.toString(); logger.debug("Filename:" + t); } }
发表这个例子,因为我很难理解如何通过Bryan给出的#1例子中的文件名参数,在Stream-result上使用foreach –
希望这可以帮助。
此代码已准备好在Windows上运行
public static void main(String... args) { File[] files = new File("C:\\").listFiles(); getFile(files); } public static void getFile(File[] files) { for (File file : files) { if (file.isDirectory()) { getFile(file.listFiles()); } else { System.out.println("File: " + file.toString()); } } }
基于堆垛机的答案。 这里是一个在JSP中工作的解决scheme,没有任何外部库,所以你可以把它放在你的服务器的任何地方:
<!DOCTYPE html> <%@ page session="false" %> <%@ page import="java.util.*" %> <%@ page import="java.io.*" %> <%@ page contentType="text/html; charset=UTF-8" %> <%! public List<String> files = new ArrayList<String>(); /** Fills files array with all sub-files. */ public void walk( File root ) { File[] list = root.listFiles(); if (list == null) return; for ( File f : list ) { if ( f.isDirectory() ) { walk( f ); } else { files.add(f.getAbsolutePath()); } } } %> <% files.clear(); File jsp = new File(request.getRealPath(request.getServletPath())); File dir = jsp.getParentFile(); walk(dir); String prefixPath = dir.getAbsolutePath() + "/"; %>
那么你只是做一些事情:
<ul> <% for (String file : files) { %> <% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %> <li><%=file.replace(prefixPath, "")%></li> <% } %> <% } %> </ul>