首页 文章

以Java的形式递归列出文件

提问于
浏览 1028 次
204

如何以递归方式列出Java中目录下的所有文件?框架是否提供任何实用程序?

我看到了很多hacky实现 . 但没有来自框架或nio

20 回答

  • 5

    Java 8提供了一个很好的流来处理树中的所有文件 .

    Files.walk(Paths.get(path))
            .filter(Files::isRegularFile)
            .forEach(System.out::println);
    

    这提供了一种遍历文件的自然方式 . 由于它是一个流,你可以对结果进行所有不错的流操作,如限制,分组,映射,早退等 .

    UPDATE :我可能会指出,如果你需要检查文件属性,那么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,大多是因为有's overloads and it'更方便 .

    TESTS :根据要求,我提供了许多答案的性能比较 . 看看Github project which contains results and a test case .

  • 1

    FileUtilsiterateFileslistFiles方法 . 试一试 . (来自commons-io

    编辑:您可以check here获取不同方法的基准 . 似乎commons-io方法很慢,所以选择一些更快的方法from here(如果重要的话)

  • 1

    //准备好了

    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:\\" );
        }
    
    }
    
  • 243

    Java 7将有Files.walkFileTree

    如果提供起点和文件访问者,它将在文件访问者调用文件树中的文件时调用各种方法 . 我们希望人们在开发递归副本,递归移动,递归删除或递归操作时使用它,这些操作可以设置权限或对每个文件执行其他操作 .

    现在有一整个Oracle tutorial on this question .

  • 11

    无需外部库 .
    返回一个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;
    }
    
  • 8

    我会用以下的东西:

    public void list(File file) {
        System.out.println(file.getName());
        File[] children = file.listFiles();
        for (File child : children) {
            list(child);
        }
    }
    

    System.out.println就是指示对文件执行某些操作 . 没有必要区分文件和目录,因为普通文件只有零个孩子 .

  • 16

    只需使用简单的递归自己编写:

    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;
    }
    
  • 7

    对于这种简单的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);
        }
      }
    }
    
  • 23

    使用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;
        }
    }
    
  • 1

    我认为这应该做的工作:

    File dir = new File(dirname);
    String[] files = dir.list();
    

    这样你就有了文件和目录 . 现在使用递归并对dirs执行相同的操作( File 类具有 isDirectory() 方法) .

  • 2

    在Java 8中,我们现在可以使用Files实用程序来遍历文件树 . 非常简单 .

    Files.walk(root.toPath())
          .filter(path -> !Files.isDirectory(path))
          .forEach(path -> System.out.println(path));
    
  • -1

    除了递归遍历之外,还可以使用基于访问者的方法 .

    下面的代码是使用基于访问者的方法进行遍历 . 预计程序的输入是遍历的根目录 .

    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);
            }
        }
    }
    
  • 66

    此代码已准备好运行

    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);
            }
        }
    }
    
  • 0

    您可以使用以下代码以递归方式获取特定文件夹或目录的文件列表 .

    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());
                }
            }
        }
    
  • 3

    具有单个列表的非递归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);
            }
        }
    
  • 157

    我的版本(当然我可以使用Java 8内置的walk ;-)):

    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;
        }
    
  • 4
    private void fillFilesRecursively(File file, List<File> resultFiles) {
            if (file.isFile()) {
                resultFiles.add(file);
            } else {
                for (File child : file.listFiles()) {
                    fillFilesRecursively(child, resultFiles);
                }
            }
        }
    
  • 130

    示例在目录中递送* .csv文件递归搜索使用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示例中传递filename参数,使用foreach on Stream-result -

    希望这可以帮助 .

  • 0

    这是一个使用 recursion 的简单但完美的解决方案:

    public static List<Path> listFiles(String rootDirectory)
    {
        List<Path> files = new ArrayList<>();
        listFiles(rootDirectory, files);
    
        return files;
    }
    
    private static void listFiles(String path, List<Path> collectedFiles)
    {
        File root = new File(path);
        File[] files = root.listFiles();
    
        if (files == null)
        {
            return;
        }
    
        for (File file : files)
        {
            if (file.isDirectory())
            {
                listFiles(file.getAbsolutePath(), collectedFiles);
            } else
            {
                collectedFiles.add(file.toPath());
            }
        }
    }
    
  • 11

    基于堆垛机答案 . 这是一个在JSP中工作的解决方案,没有任何外部库,因此您几乎可以将它放在服务器上的任何位置:

    <!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>
    

相关问题