6

How to implement an algorithm in Java 8, given a start directory and a filename, that searches for the file in the given directory or any sub-directories which are nested not deeper than 5 levels.

For example consider the following directory structure:

Folder 1
   Folder 2
      Folder 3
        Folder 4
            Folder 5
                Folder 6
                    nfiles.txt....
                MyFile.txt
                xfile.txt
            filesInFolder4....
        filesInFolder3...
   .....

The algorithm should search for the file up to files containd in the Folder 5 and report if a file with given filename exists?

How to do that using Java 8?

KayV
  • 12,987
  • 11
  • 98
  • 148
  • 2
    Show what have you tried. – Holger Dec 08 '16 at 11:10
  • @Holger I am trying Java NIO's file package and did not find any solution yet. – KayV Dec 08 '16 at 11:42
  • 2
    Note the `maxDepth` parameter in [`Files.walkFileTree(Path start, Set options, int maxDepth, FileVisitor super Path> visitor)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#walkFileTree-java.nio.file.Path-java.util.Set-int-java.nio.file.FileVisitor-). Without an actual problem statement describing what is failing when trying to use this method (or any of the alternatives), it’s impossible to tell you how to solve this. – Holger Dec 08 '16 at 11:52
  • Files.walkFileTree seems more complex then Files.find and Files.walk. – KayV Dec 08 '16 at 12:16
  • I never said that `Files.walkFileTree` was the easiest solution. Before that comment, you said you “did not find *any* solution”. Now you’re even telling me that there are easier solutions, so obviously, it helped… – Holger Dec 09 '16 at 09:16
  • In this answer, "Files.walk" is what you are looking https://stackoverflow.com/questions/1844688/read-all-files-in-a-folder – jmgoyesc Sep 26 '17 at 14:01

4 Answers4

15

Please have a look at Files.find method.

try (Stream<Path> stream = Files.find(Paths.get("Folder 1"), 5,
            (path, attr) -> path.getFileName().toString().equals("Myfile.txt") )) {
        System.out.println(stream.findAny().isPresent());
} catch (IOException e) {
        e.printStackTrace();
}
Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
  • This will return either true or false. I want the exact file location. – KayV Dec 08 '16 at 12:53
  • 1
    @KaranVerma `stream.forEach(System.out::println);` it will give you a full path to the file – Anton Balaniuc Dec 08 '16 at 12:57
  • 1
    You need to add the 4th parameter to follow symbolic lins: FileVisitOption.FOLLOW_LINKS. Why in Java so many such basic task is so painful? Can't believe you need to read 3+ articles and do your own modifications to get it done. In C#, read all text/read all line/find files in all subdirectories is just easy/elegant/intuitive. Yes you can readAllText with Java, but you need Java 11.... – jw_ Sep 24 '19 at 00:36
1

I find solution working with Files.find and Files.walk as follows:

// Finding a file upto x level in File Directory using NIO Files.find
    Path start = Paths.get("/Users/***/Documents/server_pull");
    int maxDepth = 5;
    try(Stream<Path> stream = Files.find(start, 
                                        maxDepth, 
                                        (path, attr) -> String.valueOf(path).endsWith(".json"))){
        String fileName = stream
                            .sorted()
                            .map(String::valueOf)
                            .filter((path) -> {
                                //System.out.println("In Filter : "+path);
                                return String.valueOf(path).endsWith("system_health_12_55_TestServer.json");
                            })
                            .collect(Collectors.joining());
        System.out.println("fileName : "+fileName);
    }catch(Exception e){
        e.printStackTrace();
    }

// Finding a file upto x level in File Directory using NIO Files.walk

    Path startWalk = Paths.get("/Users/***/Documents/server_pull");
    int depth = 5;
    try( Stream<Path> stream1 = Files.walk(startWalk, 
                                            depth)){
        String walkedFile = stream1
                            .map(String::valueOf)
                            .filter(path -> {
                                return String.valueOf(path).endsWith("system_health_12_55_TestServer.json");
                            })
                            .sorted()
                            .collect(Collectors.joining());
        System.out.println("walkedFile = "+walkedFile);

    }catch(Exception e){
        e.printStackTrace();
    }

It seems more simpler than walkFileTree...

KayV
  • 12,987
  • 11
  • 98
  • 148
  • 1
    You don't really need second `filter` just use `String.valueOf(path).endsWith("system_health_12_55_TestServer.json")` in the `find` method. – Anton Balaniuc Dec 08 '16 at 12:41
  • To get the ouput as follows: fileName : /Users/bng/Documents/server_pull/system_health_12_9_TestServer_India_172_20_12_2.json walkedFile = /Users/bng/Documents/server_pull/system_health_12_9_TestServer_India_172_20_12_2.json, I used double filtering. – KayV Dec 08 '16 at 12:54
1
public static String getAdobeExePath(String basePath, String exeName) {
    File[] files = new File(basePath).listFiles();
    String foundPath;
    for (int i = 0; i < files.length; i++) {
        if (files[i].isDirectory()) {
            foundPath = getAdobeExePath(files[i].getAbsolutePath(), exeName);
            if (foundPath != null) {
                return foundPath;
            }
        }else {
            if (exeName.equals(files[i].getName())) {
                return files[i].getAbsolutePath();
            }
        }
    }
    return null;
}

This is using recursion.

0

I did a little more down drill on the problem and found a way to do this in a synchronised manner using ForkJoinPool as follows:

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;



public class ForkJoinFolderProcessor {

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();


        MyFolderProcessor hadoop = new MyFolderProcessor("/Users/*****/backups/h/", "log");
        MyFolderProcessor t8 = new MyFolderProcessor("/Users/*******/apache-tomcat-9.0.2", "log");
        MyFolderProcessor t9 = new MyFolderProcessor("/Users/******/apache-tomcat-8.5.20", "log");

        pool.execute(hadoop);
        pool.execute(t8);
        pool.execute(t9);

        do {
            System.out.println("---------------------");
            System.out.println("Parallelism : "+pool.getParallelism());
            System.out.println("Active Threads : "+pool.getActiveThreadCount());
            System.out.println("Task Count : "+pool.getQueuedTaskCount());
            System.out.println("Steal Count : "+pool.getStealCount());

            System.out.println("---------------------");

            try
             {
                TimeUnit.SECONDS.sleep(1);
             } catch (InterruptedException e)
             {
                e.printStackTrace();
             }
        }while((!hadoop.isDone()) || (!t8.isDone()) || (!t9.isDone()));

        pool.shutdown();

        List<String> results = hadoop.join();
        System.out.println("Hadoop: Files found  : " + results.size()+" "+results.toString());
        results = t8.join();
        System.out.println("T8: Files found  : " + results.size()+" "+results.toString());
        results = t9.join();
        System.out.println("T9: Files found  : " + results.size()+" "+results.toString());

    }

}

class MyFolderProcessor extends RecursiveTask<List<String>>{

    private static final long serialVersionUID = 1L;

    private final String filepath;
    private final String fileExt;

    public MyFolderProcessor(String path, String extension) {
        this.filepath = path;
        this.fileExt = extension;
    }

    @Override
    protected List<String> compute() {

        List<String> list = new ArrayList<String>();
        List<MyFolderProcessor> tasks = new ArrayList<MyFolderProcessor>();

        File file = new File(filepath);
        File content[] = file.listFiles();

        if(content != null) {
                for(File f : content) {
                    if(f.isDirectory()) {
                        MyFolderProcessor task = new MyFolderProcessor(f.getAbsolutePath(), fileExt);
                        task.fork();
                        tasks.add(task);
                    }else {
                        if(checkFile(f.getName()))
                            list.add(f.getAbsolutePath());
                    }
                }
        }
        if (tasks.size() > 50) {
            System.out.println("tasks ran."+ file.getAbsolutePath()+" "+ tasks.size());
        }
        addResultsFromTasks(list, tasks);

        return list;
    }

    private void addResultsFromTasks(List<String> list, List<MyFolderProcessor> tasks) {
        for (MyFolderProcessor item : tasks) {
            list.addAll(item.join());
        }
    }

    private boolean checkFile(String name) {
        return name.endsWith(fileExt);
    }

}

Though it is more complex solution, but it works pretty well in case of multi threaded environment.

KayV
  • 12,987
  • 11
  • 98
  • 148