Reputation: 2763
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
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
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 String
s 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
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
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;
}
}
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