Akshay
Akshay

Reputation: 2763

Getting the path of the required folder and its content

I am trying to get the paths of all the contents of a given folder, say I have a folder structure something like this:

The path to this folder is: c:\\path\\to\\folder\\docs\\

docs
|
+- someFolder (c:\\path\\to\\folder\\docs\\someFolder\\)
|   +- someText.txt (c:\\path\\to\\folder\\docs\\someFolder\\someText.txt)
+- movie.mp4 (c:\\path\\to\\folder\\docs\\movie.mp4)

What I am trying to do is that:

to get the path names as

["docs\", "docs\someFolder\someText.txt", "docs\movie.mp4"] AKA relative paths. I am using Commons IO to list out all the files and folders in a given path as:

List<String[]> paths = new ArrayList<>();


File f = new File(folderPath);

for (File k : FileUtils.listFilesAndDirs(f, TrueFileFilter.TRUE, TrueFileFilter.TRUE)) {
    paths.add(k.getPath().split(Pattern.quote(File.separator)));
 }

One way is to split the main folderPath and get its last index - where ever the docs is present (that's what I did in the above code). Then iterate over the paths array and slice it from 0 to the index where ever docs is avliable.

I tried doing Arrays.asList(k.getPath().split(Pattern.quote(File.separator))).subList(0,6).clear() but I don't know how to put this in a ist or an array.

Is there any alternative to this?

Update

The reason why I need an alternative is that, I can't add Arrays.asList(k.getPath().split(Pattern.quote(File.separator))).subList(0,6).clear() to an array list as clear returns nothing. Also I just don't know how to add Arrays.asList(k.getPath().split(Pattern.quote(File.separator))) to a list of List<String[]> paths = new ArrayList<>() if I do this I get an error as:

Error:(162, 18) java: no suitable method found for add(java.util.List<java.lang.String>)
    method java.util.Collection.add(java.lang.String[]) is not applicable
      (argument mismatch; no instance(s) of type variable(s) T exist so that java.util.List<T> conforms to java.lang.String[])
    method java.util.List.add(java.lang.String[]) is not applicable
      (argument mismatch; no instance(s) of type variable(s) T exist so that java.util.List<T> conforms to java.lang.String[])

I have no idea what that means, but if I change List<String[]> paths = new ArrayList<>() to List<Object> paths = new ArrayList<>() it works and again there is a problem with Object. It's confusing.

Upvotes: 2

Views: 1408

Answers (4)

c0der
c0der

Reputation: 18792

To get a path relative to other path import use relativize of java Path:

//import java.nio.file.Path;
public static void main(String[] args) {

    List<String> paths = getPaths("c:\\path\\to\\folder\\docs\\", "c:\\path\\to\\folder");
    paths.forEach(p ->  System.out.println(p));
}

private static List<String> getPaths(String sourcePath, String sourceParentPath) {

    List<String> paths =  new ArrayList<>();
    getPaths(sourcePath, Paths.get(sourceParentPath), paths);
    return paths;
}

private static void getPaths(String sourcePath,Path parent, List<String> paths) {

    paths.add(parent.relativize(Paths.get(sourcePath)).toString());

    File file = new File(sourcePath);

    if( ! file.isDirectory()) {//if directory, search it
        return;
    }

    if(file.list() == null) {//for abstract path or errors
        return;
    }

    for (String fileName: file.list() ){

        getPaths((sourcePath+"\\"+fileName), parent, paths);
    }
}

Upvotes: 1

Slaw
Slaw

Reputation: 45806

If you can use NIO this can be much simpler.

public List<Path> findFilesAsRelativePaths(Path directory) throws IOException {
    try (Stream<Path> stream = Files.find(directory, Integer.MAX_VALUE, (path, attrs) -> attrs.isRegularFile())) {
        return stream.map(directory::relativize).collect(Collectors.toList());
    }
}

This uses java.nio.file.Files.find(Path, int, BiPredicate, FileVisitOption...)

If you need the paths as Strings you can simply call Path.toString(). Or if you need them as a File you can convert it with Path.toFile().

Also, if you want directories as well you can change (path, attrs) -> attrs.isRegularFile() to (path, attrs) -> true. Although it may just be better to use Files.walk(Path, int, FileVisitOption...).

Upvotes: 1

JKostikiadis
JKostikiadis

Reputation: 2917

Well the way I would do it is by a recursive method like the one below, I have commends inside the code to explain the process :

public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();

        // arguments are your folder and the list you
        // want to add the results
        collectFiles(new File("C:/"), list);

        for (String s : list) {
            System.out.println(s);
        }
    }

    private static void collectFiles(File folder, ArrayList<String> list) {
        // Add the current file/folder to the list
        list.add(folder.getAbsolutePath());

        // If its not a directory return cause we already add it
        if (!folder.isDirectory())
            return;

        // We found a directory so get all the files in it
        File[] listOfFiles = folder.listFiles();

        // In case the above returns null return
        if (listOfFiles == null)
            return;

        // For every file in the list
        for (File f : listOfFiles) {
            // if its a directory do a recursive call 
            if (f.isDirectory()) {
                collectFiles(f, list);
            } else {
                // we found a file so add it to the list
                list.add(f.getAbsolutePath());
            }
        }
    }

Edit :

Well asking for relative paths could be done easily just by manipulating the strings in the list, but this would be the naive approach. The best solution I can think of is to use one more parameter which will hold the relative path:

private static void collectFiles(File folder, String relativePath, ArrayList<String> list) {
        // Add the current file/folder to the list
        list.add(relativePath);

        // If its not a directory return cause we already add it
        if (!folder.isDirectory())
            return;

        // We found a directory so get all the files in it
        File[] listOfFiles = folder.listFiles();

        // In case the above returns null return
        if (listOfFiles == null)
            return;

        // For every file in the list
        for (File f : listOfFiles) {
            // if its a directory do a recursive call
            if (f.isDirectory()) {
                collectFiles(f, relativePath + File.separator + f.getName(), list);
            } else {
                // we found a file so add it to the list
                list.add(relativePath + File.separator + f.getName());
            }
        }
    }

And you just call it like :

File searchFolder = new File("C:\\Users\\Name\\Desktop");
collectFiles(searchFolder, searchFolder.getName(), list);

for (String s : list) {
    System.out.println(s);
}

Edit 2 : Well you ask the method to return the List instead so below there is that version as well :

private static ArrayList<String> collectFiles(File folder, String relativePath) {

        ArrayList<String> resultList = new ArrayList<>();
        resultList.add(relativePath);

        if (!folder.isDirectory())
            return resultList;

        File[] listOfFiles = folder.listFiles();

        if (listOfFiles == null) {
            return new ArrayList<>();
        }

        for (File f : listOfFiles) {
            if (f.isDirectory()) {
                ArrayList<String> currentResults = collectFiles(f, relativePath + File.separator + f.getName());
                resultList.addAll(currentResults);
            } else {
                resultList.add(relativePath + File.separator + f.getName());
            }
        }

        return resultList;
    }

Upvotes: 1

Amith Kumar
Amith Kumar

Reputation: 4884

If I understood your requirement right, you can just use string replace to do the job for you.

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;

public class DirectoryListing {

    public static void main(String[] args) {
        String folderPath = "c:\\path\\to\\folder\\docs\\";
        String parentDirectory = "docs";
        System.out.println(findFilePaths(folderPath, parentDirectory));
    }

    public static List<String> findFilePaths(String folderPath, String parentDirectory){
        List<String> paths = new ArrayList<>();
        File f = new File(folderPath);
        for (File k : FileUtils.listFiles(f, TrueFileFilter.TRUE, TrueFileFilter.TRUE)) {           
            paths.add(k.getPath().replace(folderPath, parentDirectory));
         }
        return paths;
    }

}

My test directory tree:

enter image description here

with this run parameters:
String folderPath = "C:\\00docs";
String parentDirectory = "docs";

result list is coming as:
[docs\00\File00.txt, docs\00\File00A.txt, docs\00docs\File00DocsA.txt, docs\01\File01.txt, docs\File00DocsP.txt]

Upvotes: 1

Related Questions