Java: how to get all subdirs recursively?
Before debugging the late-hour-out-of-bound-recursive-function: is there a command to get subdirs? giveMeSubDirs(downToPath)
?
// WARNING: RECURSION out of bound or too much data
public HashSet<FileObject> getAllDirs(String path) {
HashSet<FileObject> checkedDirs = new HashSet<FileObject>();
HashSet<FileObject> allDirs = new HashSet<FileObject>();
String startingPath = path;
File fileThing = new File(path);
FileObject fileObject = new FileObject(fileThing);
for (FileObject dir : getDirsInDir(path)) {
// SUBDIR
while ( !checkedDirs.contains(dir)
&& !(getDirsInDir(dir.getFile().getParent()).size() == 0)) {
// DO NOT CHECK TOP DIRS if any bottom dir UNCHECKED!
while ( uncheckedDirsOnLevel(path, checkedDirs).size() > 0) {
while (getDirsInDir(path).size() == 0
|| (numberOfCheckedDirsOnLevel(path, checkedDirs)==getDirsInDir(pa开发者_C百科th).size())) {
allDirs.add(new FileObject(new File(path)));
checkedDirs.add(new FileObject(new File(path)));
if(traverseDownOneLevel(path) == startingPath )
return allDirs;
//get nearer to the root
path = traverseDownOneLevel(path);
}
path = giveAnUncheckedDir(path, checkedDirs);
if ( path == "NoUnchecked.") {
checkedDirs.add(new FileObject( (new File(path)).getParentFile() ));
break;
}
}
}
}
return allDirs;
}
Summary about the code:
- Go as deep to the directory tree as possible. When there is no dir in a dir, stop, put the dir to the set, traverse up. Do not check dirs in the set.
- Stop and return the set if you reach the starting path.
- Repeat steps 1 and 2.
PREMISE: the directory-structure is finite and with a small data amount.
You can get all subdirs with the following snippet:
File file = new File("path");
File[] subdirs = file.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
});
This gets only immediate subdirs, to retrieve all of them recursively you could write:
List<File> getSubdirs(File file) {
List<File> subdirs = Arrays.asList(file.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
}));
subdirs = new ArrayList<File>(subdirs);
List<File> deepSubdirs = new ArrayList<File>();
for(File subdir : subdirs) {
deepSubdirs.addAll(getSubdirs(subdir));
}
subdirs.addAll(deepSubdirs);
return subdirs;
}
No, there is no such functionality in the Java standard API. But there is in Apache commons-io; if you don't want to include it as a library, you could also look at the source code.
Another version with no recursion, and alphabetical order. Also uses a Set to avoid loops (a problem in Unix systems with links).
public static Set<File> subdirs(File d) throws IOException {
TreeSet<File> closed = new TreeSet<File>(new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
return f1.toString().compareTo(f2.toString());
}
});
Deque<File> open = new ArrayDeque<File>();
open.push(d);
closed.add(d);
while ( ! open.isEmpty()) {
d = open.pop();
for (File f : d.listFiles()) {
if (f.isDirectory() && ! closed.contains(f)) {
open.push(f);
closed.add(f);
}
}
}
return closed;
}
The sample code above is missing ");" at the end of the statement. The correct code should be:
File file = new File("path");
File[] subdirs = file.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
});
Using recursion:
private void getAllSubFoldersInPath(File path)
{
File[] files=path.listFiles();
try {
for(File file: files)
{
if(file.isDirectory())
{
System.out.println("DIRECTORY:"+file.getCanonicalPath());
getAllSubFoldersInPath(file);
}
else
{
System.out.println("FILE: "+file.getCanonicalPath());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This is an improved code with Java 8 approach. This code will run on a Recursion basis and find the directories until the last root.
List<File> findAllSubdirs(File file) {
List<File> subdirs = Arrays.asList(file.listFiles(File::isDirectory));
subdirs = new ArrayList<File>(subdirs);
List<File> deepSubdirs = new ArrayList<File>();
for(File subdir : subdirs) {
deepSubdirs.addAll(findAllSubdirs(subdir));
}
subdirs.addAll(deepSubdirs);
return subdirs;
}
If you want only immediate subdirectories list, try with the below line of code..
List<File> subdirs = Arrays.asList(file.listFiles(File::isDirectory));
- Get all files from root file as array (@see listFiles)
- Sort just for directories by distinguishing between files & directories (@see isDirectory)
- Convert (filtered) array from step 1 & 2 to list
- Add all found directories to resulting list
- Repeat that pattern for each directory file you found in step 1, with growing resulting list
- At the end, return resulting list
All that put into some lambda magic:
private static List<File> getAllSubDirectories(File root, List<File> result) {
List<File> currentSubDirs = Arrays.asList(Objects.requireNonNull(root.listFiles(File::isDirectory), "Root file has to be directory"));
result.addAll(currentSubDirs);
currentSubDirs.forEach(file -> getAllSubDirectories(file, result));
return result;
}
Just start with root file (which should be a directory) and an empty list.
Note: Step 1 & 2 can be combined with a filter (@see listFiles(FileFilter filter))
class DirFileFilter extends FileFilter {
boolean accept(File pathname) {
return pathname.isDirectory();
}
}
DirFileFilter filter = new DirFileFilter();
HashSet<File> files = new HashSet<File>();
void rec(File root) {
// add itself to the list
files.put(root);
File[] subdirs = root.list(filter);
// bound of recursion: must return
if (subdirs.length == 0)
return;
else //this is the recursive case: can call itself
for (File file : subdirs)
rec(file);
}
精彩评论