Java - 遍历文件夹中的所有文件

9
我想要查找目录和嵌套子目录中的所有txt文件。如果找到了,我想将其从一个位置移动到另一个位置。
下面的代码在没有任何嵌套子目录的情况下可以正常工作。
问题在于,下面的代码一旦发现嵌套目录,它就只能从该特定嵌套子目录返回文件。 但是我想要在我的目录(父目录和其嵌套子目录)中找到所有的txt文件。
public class FilesFindingInDirectory {
    static ArrayList<File> al = new ArrayList<File>();
    static File fileLocation = null;
    public static void main(String[] args) throws IOException {


        File filePath = new File("C:\\Users\\Downloads");

        File[] listingAllFiles = filePath.listFiles();

        ArrayList<File> allFiles = iterateOverFiles(listingAllFiles);


                for (File file : allFiles) {
                    if(file != null) {
                        String fileName = file.getName();

                        String sourceFilepath = file.getAbsolutePath();
                        File targetFilePath = new File("D:\\TestFiles");
                        String targetPath = targetFilePath.getPath();

                        Files.move(Paths.get(sourceFilepath), Paths.get("D:\\TestFiles\\" + fileName)); 
                    }

                }
            }


public static ArrayList<File> iterateOverFiles(File[] files) {


        for (File file : files) {

            if (file.isDirectory()) {

                iterateOverFiles(file.listFiles());// Calls same method again.

            } else {

                fileLocation = findFileswithTxtExtension(file);
                if(fileLocation != null) {
                    System.out.println(fileLocation);
                    al.add(fileLocation);
                }


            }
        }

        return al;
    }

public static File findFileswithTxtExtension(File file) {

        if(file.getName().toLowerCase().endsWith("txt")) {
            return file;
        }

        return null;
    }
}

1
尽管递归结果收集部分的代码可以改进,但我测试了你的代码,它运行良好。你能详细说明你看到的问题吗?或者提供一个例子?我用包含2个txt文件的目录和另一个包含2个其他文本文件的目录测试了代码,它运行良好。我唯一能想象的是,如果文件名相同,它们最终会被覆盖在最终目标中。 - apadana
4个回答

14

您已经在使用nio文件API移动文件了,为什么不使用它来遍历文件呢?

 List<Path> txtFiles = Files.walk(Paths.get("C:\\Users\\Downloads"))
                            //use to string here, otherwise checking for path segments
                            .filter(p -> p.toString().endsWith(".txt"))
                            .collect(Collectors.toList());

如果您不需要中介列表,您也可以在foreach终端操作中运行移动操作。

Files.walk(Paths.get("C:\\Users\\Downloads"))
     .filter(p -> p.toString().endsWith(".txt"))
     .forEach(p -> {
        try {
            Files.move(p, Paths.get("D:\\TestFiles", p.getFileName().toString()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

2
我们的 Files.find 提供了一个过滤参数。 - daniu
OpenJDK文档中的Files#walk(Path)有一个API说明,指出:“为确保流操作完成后及时关闭流的打开目录,必须在try-with-resources语句或类似控制结构中使用此方法。”这是否意味着需要将您的答案中的代码包装在try-with-resources语句中?还是这个要求已经由函数式API /流的使用覆盖了? - Jonny Henly
似乎上面的API注释是在Oracle的SE 9中添加的。SE 8 Files#walk(Path, FileVisitOption)文档指出:“返回的流封装了一个或多个DirectoryStreams。如果需要及时处理文件系统资源,则应使用try-with-resources结构确保在完成流操作后调用流的close方法。在关闭的流上操作将导致IllegalStateException。” - Jonny Henly

4
从你的递归函数中移除这行代码:
return al;

将此行更改为调用递归函数:
ArrayList<File> allFiles = iterateOverFiles(listingAllFiles);

to

iterateOverFiles(listingAllFiles);

最后,将您的for循环更改为迭代静态字段al。
for (File file : allFiles) {

to

for (File file : al) {

解释:有许多方法可以为这个问题编写递归。在这种情况下,您需要一个全局变量来收集结果。每次迭代都应该添加到全局结果中,并简单返回。在所有递归调用结束时,全局变量将包含所有结果。


3
你正确地递归调用了函数,但之后你却忽略了它的返回值。相反,你应该将它附加到结果列表中:
public static List<File> iterateOverFiles(File[] files) {
    List<File> result = new ArrayList<>();
    for (File file : files) {
        if (file.isDirectory()) {
            result.addAll(iterateOverFiles(file.listFiles()); // Here!
        } else {
            fileLocation = findFileswithTxtExtension(file);
            if(fileLocation != null) {
                result.add(fileLocation);
            }
        }
    }

    return result;
}

0

只需遍历目录,跳过任何非目录条目和没有所需扩展名的条目。将所有具有正确扩展名的文件添加到结果中,并对每个目录递归执行此操作。

public class FilesFindingInDirectory {
   public static void main(String[] args) throws IOException {


    File filePath = new File("C:\\Users\\Downloads");


    Collection<File> allFiles = findFiles(filePath, ".txt");
    allFiles.forEach(file -> {
                    String fileName = file.getName();

                    String sourceFilepath = file.getAbsolutePath();
                    File targetFilePath = new File("D:\\TestFiles");
                    String targetPath = targetFilePath.getPath();

                    Files.move(Paths.get(sourceFilepath), Paths.get("D:\\TestFiles\\" + fileName)); 
                }

            }
        }

public static List<File> findFiles(File dir, String extension) {
    File[] files = dir.listFiles(f -> f.isDirectory() || f.getName().toLowerCase().endsWith(extension);
    ArrayList<File> result = new ArrayList<>();  
    if (files != null) {
       for (File file : files) {

        if (file.isDirectory()) {
            result.addAll(findFiles(file, extension);
        } else {
            result.add(file);
        }

    }

    return result;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接