简体   繁体   English

检索文件夹和子文件夹以使用尾递归在java中读取文件

[英]Retrieve folders and subfolders to read a file in java using tail recursion

I am using normal recursion to a method to iterate and to get files from folders and subfolders in java. 我正在使用正常的递归方法来迭代并从java中的文件夹和子文件夹中获取文件。

Can someone help me in changing that to tail recursion method? 有人可以帮助我改变尾部递归方法吗? I couldn't understand what tail recursion is. 我无法理解尾递归是什么。 It will be useful for me to understand. 这对我来说很有用。

public void findFiles(String filePath) throws IOException {
    List<File> files = Files.list(Paths.get(filePath))
                            .map(path -> path.toFile())
                            .collect(Collectors.toList());

    for(File file: files) {
        if(file.isDirectory()){ 
                if(file.list().length == 0){
                        boolean isDeleted = file.delete();

                }else{
                    findFiles(file.getAbsolutePath());
                }
        }else{
            //process files
        }
    }
}

This is the normal recursion I have, can someone help me to write a tail recursion for this? 这是我的正常递归,有人可以帮我写这个尾递归吗?

I tried a way, But I am not sure whether this is tail recursion and how it works. 我尝试了一种方法,但我不确定这是否是尾递归及其工作原理。

public static void findFiles(String filePath) throws IOException{
    List<File> files = Files.list(Paths.get(filePath))
                            .map(path -> path.toFile())
                            .collect(Collectors.toList());

    for(File file: files) {
        if(file.isDirectory() && file.list().length == 0){
             boolean isDeleted = file.delete();
        }else if(!file.isDirectory()){
                System.out.println("Processing files!!!" +  file.getAbsolutePath());
        }
        if(file.isDirectory()) {
                findFiles(file.getAbsolutePath());
        }
    }

}

Thanks in Advance. 提前致谢。

Tail recursion is a special kind of recursion which does not do anything after the recursive call but return. 尾递归是一种特殊的递归, 它在递归调用之后不做任何事情但返回。

Some programming languages take advantage of this by optimising the call stack, so that if you have a very deep recursion you don't end up with stack overflows (apart from the memory and invocation efficiency gains themselves). 一些编程语言通过优化调用堆栈来利用这一点,因此如果你有一个非常深的递归,你不会最终出现堆栈溢出(除了内存和调用效率增益本身)。

The trick that is often used is that you add an extra accumulator parameter, which takes any outstanding data to be processed. 经常使用的技巧是添加一个额外的累加器参数,该参数可以处理任何未完成的数据。 Since this might make the recursive function less usable, it is usually done separately, so that to the user of your function it appears simple. 由于这可能使递归函数不太可用,因此它通常是单独完成的,因此对于函数的用户来说它看起来很简单。

So in your example it would be like this, the normal findFiles() just prepares for the recursive call, while the private findFilesRecursive() is doing the tail recursive work. 所以在你的例子中就是这样,正常的findFiles()只是准备递归调用,而private findFilesRecursive()正在进行尾递归工作。

public void findFiles(String filePath) throws IOException {
  //we use a Deque<> for Last In First Out ordering (to keep subfolders with their parent)
  Deque<Path> paths = new ArrayDeque<Path>();  
  paths.add(Paths.get(filePath);
  return findFilesRecursive(paths);  
}

private void findFilesRecursive(Deque<Path> pending) {
  if (pending.isEmpty()) {
    //base case, we are ready
    return;
  }

  Path path = pending.removeFirst();
  if (Files.isRegularFile(path)) {
    //todo: process the file

  } else {
      //it is a directory, queue its subfolders for processing
     List<Path> inside = Files.list(path).collect(Collectors.toList());
     if (inside.isEmpty() {
       Files.delete(path);
     } else {
       //we use LIFO so that subfolders get processed first
       inside.forEach(pending::addFirst);
     }
  }

  //tail recursion, we do nothing after we call it
  return findFilesRecursive(pending);  
}

Note that Java doesn't ( yet ) take advantage of tail recursion. 请注意,Java( 尚未 )利用尾递归。 Other programming languages like Scala and Kotlin do. 其他编程语言,如Scala和Kotlin。

Side note, Path is generally more powerful from the old File , you don't need to change a Path to a File in your case. 旁注, Path通常比旧File更强大,您不需要在您的情况下更改File Path

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM