How to scan a folder in Java? - java

How can I get list all the files within a folder recursively in Java?

Not sure how you want to represent the tree? Anyway here's an example which scans the entire subtree using recursion. Files and directories are treated alike. Note that File.listFiles() returns null for non-directories.
public static void main(String[] args) {
Collection<File> all = new ArrayList<File>();
addTree(new File("."), all);
System.out.println(all);
}
static void addTree(File file, Collection<File> all) {
File[] children = file.listFiles();
if (children != null) {
for (File child : children) {
all.add(child);
addTree(child, all);
}
}
}
Java 7 offers a couple of improvements. For example, DirectoryStream provides one result at a time - the caller no longer has to wait for all I/O operations to complete before acting. This allows incremental GUI updates, early cancellation, etc.
static void addTree(Path directory, Collection<Path> all)
throws IOException {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(directory)) {
for (Path child : ds) {
all.add(child);
if (Files.isDirectory(child)) {
addTree(child, all);
}
}
}
}
Note that the dreaded null return value has been replaced by IOException.
Java 7 also offers a tree walker:
static void addTree(Path directory, final Collection<Path> all)
throws IOException {
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
all.add(file);
return FileVisitResult.CONTINUE;
}
});
}

import java.io.File;
public class Test {
public static void main( String [] args ) {
File actual = new File(".");
for( File f : actual.listFiles()){
System.out.println( f.getName() );
}
}
}
It displays indistinctly files and folders.
See the methods in File class to order them or avoid directory print etc.
http://java.sun.com/javase/6/docs/api/java/io/File.html

You can also use the FileFilter interface to filter out what you want. It is best used when you create an anonymous class that implements it:
import java.io.File;
import java.io.FileFilter;
public class ListFiles {
public File[] findDirectories(File root) {
return root.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}});
}
public File[] findFiles(File root) {
return root.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isFile();
}});
}
}

public static void directory(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
if (file.listFiles() != null)
directory(file);
}
}
Here dir is Directory to be scanned. e.g. c:\

Visualizing the tree structure was the most convenient way for me :
public static void main(String[] args) throws IOException {
printTree(0, new File("START/FROM/DIR"));
}
static void printTree(int depth, File file) throws IOException {
StringBuilder indent = new StringBuilder();
String name = file.getName();
for (int i = 0; i < depth; i++) {
indent.append(".");
}
//Pretty print for directories
if (file.isDirectory()) {
System.out.println(indent.toString() + "|");
if(isPrintName(name)){
System.out.println(indent.toString() + "*" + file.getName() + "*");
}
}
//Print file name
else if(isPrintName(name)) {
System.out.println(indent.toString() + file.getName());
}
//Recurse children
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++){
printTree(depth + 4, files[i]);
}
}
}
//Exclude some file names
static boolean isPrintName(String name){
if (name.charAt(0) == '.') {
return false;
}
if (name.contains("svn")) {
return false;
}
//.
//. Some more exclusions
//.
return true;
}

In JDK7, "more NIO features" should have methods to apply the visitor pattern over a file tree or just the immediate contents of a directory - no need to find all the files in a potentially huge directory before iterating over them.

Related

Read Sub directory and specific files in Java

I need find all the java files in a directory
private void search(File directory) {
if (directory.isDirectory()) {
File[] javaFilesLs = directory.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".java");
// return name.toLowerCase().endsWith(".java") || dir.isDirectory();
}
});
if (directory.canRead()) {
assert javaFilesLs != null;
for (File temp : javaFilesLs) {
if (temp.isDirectory()) {
search(temp);
} else {
fileList.add(temp.getAbsolutePath());
}
}
}
}
}
When I use the commented line it finds the subdirectory and all the files not only ".java" files.
The reason why you get all paths using the commented line, is that dir.isDirectory() will return true for all files.
Take a look at the documentation of FilenameFilter. It specifies that dir is "the directory in which the file was found."
So instead of looking at dir, you must test if name represents a directory. There may be smarter methods, but it can be done like this:
new File(dir.toPath().toString(), name).isDirectory() // returns true for directories
The whole snippet thus looks like this:
private void search(File directory) {
if (directory.isDirectory()) {
File[] javaFilesLs = directory.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".java") || new File(dir.toPath().toString(), name).isDirectory();
}
});
if (directory.canRead()) {
assert javaFilesLs != null;
for (File temp : javaFilesLs) {
if (temp.isDirectory()) {
search(temp);
} else {
fileList.add(temp.getAbsolutePath());
}
}
}
}
}
Alternatively, Java 8 adds Files.walk which implements the recursion for you as a Stream.
private void search(File directory) throws IOException {
Files.walk(directory.toPath())
.filter(f -> {
return f.getFileName().toString().endsWith(".java");
})
.forEach(f -> fileList.add(f.toFile().getAbsolutePath()));
}

how to find all the files of given extension in whole harddisk [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
i have written a program that finds all the files of specified type by passing its extension.
my problem is, program is finding files in C drive only, but i want to search in for whole hard disk. here is my program sample
public class Find {
public static class Finder extends SimpleFileVisitor<Path> {
private final PathMatcher matcher;
private int numMatches = 0;
Finder(String pattern)
{
matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
}
// Compares the glob pattern against
// the file or directory name.
void find(Path file)
{
Path name = file.getFileName();
if (name != null && matcher.matches(name))
{
numMatches++;
System.out.println(file);
}
}
// Prints the total number of
// matches to standard out.
void done()
{
System.out.println("Matched: "+ numMatches);
}
// Invoke the pattern matching
// method on each file.
//#Override
public FileVisitResult visitFile(Path file,BasicFileAttributes attrs)
{
find(file);
return CONTINUE;
}
// Invoke the pattern matching
// method on each directory.
//#Override
public FileVisitResult preVisitDirectory(Path dir,BasicFileAttributes attrs)
{
find(dir);
return CONTINUE;
}
//#Override
public FileVisitResult visitFileFailed(Path file,IOException exc)
{
System.err.println(exc);
return CONTINUE;
}
}
static void usage()
{
System.err.println("java Find <path>" +" -name \"<glob_pattern>\"");
System.exit(-1);
}
public static void main(String[] args)throws IOException
{
if (args.length < 2 )
{
usage();
}
Path startingDir = Paths.get(args[0]);
String pattern = args[1];
Finder finder = new Finder(pattern);
Files.walkFileTree(startingDir, finder);
finder.done();
}
}
You can use the File.listRoots() method to find all drives on Windows. After that just do an independent search on each drive.
Using the new API (java.nio.file) there's another way: FileSystem.getDefault().getRootDirectories().
for (Path startingDir : FileSystem.getDefault().getRootDirectories()) {
// find files here
}
Try something like this
File folder = new File("D:\\DestFile");
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles) {
if (file.isFile()&& (file.getName().substring(file.getName().lastIndexOf('.')+1).equals("your_type"))) {// txt or docx or something
// do something
}
}
Try this. you can read all file in your PC by this
public static void main(String[] args) {
File[] paths = File.listRoots();
for(File directory:paths){
getFile(directory.toString());
}
}
public static void getFile(String directoryName) {
File directory = new File(directoryName);
File[] fList = directory.listFiles();
if(fList!=null){
for (File file : fList) {
if (file.isFile()) {
System.out.println(file.toString());
} else if (file.isDirectory()) {
getFile(file.getAbsolutePath());
}
}
}
}

Filtering and selecting files from a directory

I have an application right now that selects files from a directory. what I want to do is be able to have a feature where you can put in a file extension such as .gif, .txt etc.. and after a button is clicked the application will run through the directory and find and select all files of that type. The only code I have to show is of my current application which has none of this. Was hoping for a point in the right direction or some advice.
private List<File> getMatchingFiles(File parent, final String extension) {
File[] files = parent.listFiles(new FileFilter() {
public boolean accept(File dir) {
String name = dir.getName();
if(name.endsWith(extension)) {
return true;
}
}
});
List<File> retval = Arrays.asList( files );
return retval;
}
For use in a JFileChooser, all the answers so far offered are sub-optimal. Instead implement JFileChooser.setFileFilter(javax.swing.filechooser.FileFilter) for the best user experience.
It might end up looking something like this1:
Image obtained using code courtesy of A Sample FileChooser Program.
What you are looking for is probably the java.io.File#list(filter).
edit: If you want the entire file system be searched, then you need to recursively scan every direcotry:
public static void filter (String dirname, List<File> result) {
try {
for (String f : new File(dirname).list()) {
String filename = dirname + f;
File theFile = new File(filename);
if (theFile.isDirectory()) {
filter(filename + "/", result);
} else if (new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".gif");
}
}.accept(theFile)) {
result.add(theFile);
}
}
} catch (Exception e) {
// may raise null-pointer when access denied
}
}
public static void main(String[] args) {
List<File> result = new ArrayList<File>();
filter("F:/", result);
System.out.println(result.size());
}
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return (!name.endsWith(".gif")
}
};

List all files from a directory recursively with Java

I have this function that prints the name of all the files in a directory recursively. The problem is that my code is very slow because it has to access a remote network device with every iteration.
My plan is to first load all the files from the directory recursively and then after that go through all files with the regex to filter out all the files I don't want. Is there a better solution?
public static printFnames(String sDir) {
File[] faFiles = new File(sDir).listFiles();
for (File file : faFiles) {
if (file.getName().matches("^(.*?)")) {
System.out.println(file.getAbsolutePath());
}
  if (file.isDirectory()) {
printFnames(file.getAbsolutePath());
}
}
}
This is just a test. Later on I'm not going to use the code like this; instead I'm going to add the path and modification date of every file which matches an advanced regex to an array.
Assuming this is actual production code you'll be writing, then I suggest using the solution to this sort of thing that's already been solved - Apache Commons IO, specifically FileUtils.listFiles(). It handles nested directories, filters (based on name, modification time, etc).
For example, for your regex:
Collection files = FileUtils.listFiles(
dir,
new RegexFileFilter("^(.*?)"),
DirectoryFileFilter.DIRECTORY
);
This will recursively search for files matching the ^(.*?) regex, returning the results as a collection.
It's worth noting that this will be no faster than rolling your own code, it's doing the same thing - trawling a filesystem in Java is just slow. The difference is, the Apache Commons version will have no bugs in it.
In Java 8, it's a 1-liner via Files.find() with an arbitrarily large depth (eg 999) and BasicFileAttributes of isRegularFile()
public static printFnames(String sDir) {
Files.find(Paths.get(sDir), 999, (p, bfa) -> bfa.isRegularFile()).forEach(System.out::println);
}
To add more filtering, enhance the lambda, for example all jpg files modified in the last 24 hours:
(p, bfa) -> bfa.isRegularFile()
&& p.getFileName().toString().matches(".*\\.jpg")
&& bfa.lastModifiedTime().toMillis() > System.currentMillis() - 86400000
This is a very simple recursive method to get all files from a given root.
It uses the Java 7 NIO Path class.
private List<String> getFileNames(List<String> fileNames, Path dir) {
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path path : stream) {
if(path.toFile().isDirectory()) {
getFileNames(fileNames, path);
} else {
fileNames.add(path.toAbsolutePath().toString());
System.out.println(path.getFileName());
}
}
} catch(IOException e) {
e.printStackTrace();
}
return fileNames;
}
With Java 7, a faster way to walk through a directory tree was introduced with the Paths and Files functionality. They're much faster than the "old" File way.
This would be the code to walk through and check path names with a regular expression:
public final void test() throws IOException, InterruptedException {
final Path rootDir = Paths.get("path to your directory where the walk starts");
// Walk thru mainDir directory
Files.walkFileTree(rootDir, new FileVisitor<Path>() {
// First (minor) speed up. Compile regular expression pattern only one time.
private Pattern pattern = Pattern.compile("^(.*?)");
#Override
public FileVisitResult preVisitDirectory(Path path,
BasicFileAttributes atts) throws IOException {
boolean matches = pattern.matcher(path.toString()).matches();
// TODO: Put here your business logic when matches equals true/false
return (matches)? FileVisitResult.CONTINUE:FileVisitResult.SKIP_SUBTREE;
}
#Override
public FileVisitResult visitFile(Path path, BasicFileAttributes mainAtts)
throws IOException {
boolean matches = pattern.matcher(path.toString()).matches();
// TODO: Put here your business logic when matches equals true/false
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path path,
IOException exc) throws IOException {
// TODO Auto-generated method stub
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path path, IOException exc)
throws IOException {
exc.printStackTrace();
// If the root directory has failed it makes no sense to continue
return path.equals(rootDir)? FileVisitResult.TERMINATE:FileVisitResult.CONTINUE;
}
});
}
The fast way to get the content of a directory using Java 7 NIO:
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.nio.file.Path;
...
Path dir = FileSystems.getDefault().getPath(filePath);
DirectoryStream<Path> stream = Files.newDirectoryStream(dir);
for (Path path : stream) {
System.out.println(path.getFileName());
}
stream.close();
Java's interface for reading filesystem folder contents is not very performant (as you've discovered). JDK 7 fixes this with a completely new interface for this sort of thing, which should bring native level performance to these sorts of operations.
The core issue is that Java makes a native system call for every single file. On a low latency interface, this is not that big of a deal - but on a network with even moderate latency, it really adds up. If you profile your algorithm above, you'll find that the bulk of the time is spent in the pesky isDirectory() call - that's because you are incurring a round trip for every single call to isDirectory(). Most modern OSes can provide this sort of information when the list of files/folders was originally requested (as opposed to querying each individual file path for it's properties).
If you can't wait for JDK7, one strategy for addressing this latency is to go multi-threaded and use an ExecutorService with a maximum # of threads to perform your recursion. It's not great (you have to deal with locking of your output data structures), but it'll be a heck of a lot faster than doing this single threaded.
In all of your discussions about this sort of thing, I highly recommend that you compare against the best you could do using native code (or even a command line script that does roughly the same thing). Saying that it takes an hour to traverse a network structure doesn't really mean that much. Telling us that you can do it native in 7 second, but it takes an hour in Java will get people's attention.
This will work just fine and it’s recursive.
File root = new File("ROOT PATH");
for (File file : root.listFiles())
{
getFilesRecursive(file);
}
private static void getFilesRecursive(File pFile)
{
for(File files : pFile.listFiles())
{
if(files.isDirectory())
{
getFilesRecursive(files);
}
else
{
// Do your thing
//
// You can either save in HashMap and
// use it as per your requirement
}
}
}
I personally like this version of FileUtils. Here's an example that finds all mp3s or flacs in a directory or any of its subdirectories:
String[] types = {"mp3", "flac"};
Collection<File> files2 = FileUtils.listFiles(/path/to/your/dir, types , true);
This will work fine
public void displayAll(File path){
if(path.isFile()){
System.out.println(path.getName());
}else{
System.out.println(path.getName());
File files[] = path.listFiles();
for(File dirOrFile: files){
displayAll(dirOrFile);
}
}
}
Java 8
public static void main(String[] args) throws IOException {
Path start = Paths.get("C:\\data\\");
try (Stream<Path> stream = Files.walk(start, Integer.MAX_VALUE)) {
List<String> collect = stream
.map(String::valueOf)
.sorted()
.collect(Collectors.toList());
collect.forEach(System.out::println);
}
}
public class GetFilesRecursive {
public static List <String> getFilesRecursively(File dir){
List <String> ls = new ArrayList<String>();
for (File fObj : dir.listFiles()) {
if(fObj.isDirectory()) {
ls.add(String.valueOf(fObj));
ls.addAll(getFilesRecursively(fObj));
} else {
ls.add(String.valueOf(fObj));
}
}
return ls;
}
public static List <String> getListOfFiles(String fullPathDir) {
List <String> ls = new ArrayList<String> ();
File f = new File(fullPathDir);
if (f.exists()) {
if(f.isDirectory()) {
ls.add(String.valueOf(f));
ls.addAll(getFilesRecursively(f));
}
} else {
ls.add(fullPathDir);
}
return ls;
}
public static void main(String[] args) {
List <String> ls = getListOfFiles("/Users/srinivasab/Documents");
for (String file:ls) {
System.out.println(file);
}
System.out.println(ls.size());
}
}
This function will probably list all the file name and its path from its directory and its subdirectories.
public void listFile(String pathname) {
File f = new File(pathname);
File[] listfiles = f.listFiles();
for (int i = 0; i < listfiles.length; i++) {
if (listfiles[i].isDirectory()) {
File[] internalFile = listfiles[i].listFiles();
for (int j = 0; j < internalFile.length; j++) {
System.out.println(internalFile[j]);
if (internalFile[j].isDirectory()) {
String name = internalFile[j].getAbsolutePath();
listFile(name);
}
}
} else {
System.out.println(listfiles[i]);
}
}
}
it feels like it's stupid access the
filesystem and get the contents for
every subdirectory instead of getting
everything at once.
Your feeling is wrong. That's how filesystems work. There is no faster way (except when you have to do this repeatedly or for different patterns, you can cache all the file paths in memory, but then you have to deal with cache invalidation i.e. what happens when files are added/removed/renamed while the app runs).
Just so you know isDirectory() is quite a slow method. I'm finding it quite slow in my file browser. I'll be looking into a library to replace it with native code.
Another optimized code
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class GetFilesRecursive {
public static List <String> getFilesRecursively(File dir){
List <String> ls = new ArrayList<String>();
if (dir.isDirectory())
for (File fObj : dir.listFiles()) {
if(fObj.isDirectory()) {
ls.add(String.valueOf(fObj));
ls.addAll(getFilesRecursively(fObj));
} else {
ls.add(String.valueOf(fObj));
}
}
else
ls.add(String.valueOf(dir));
return ls;
}
public static void main(String[] args) {
List <String> ls = getFilesRecursively(new File("/Users/srinivasab/Documents"));
for (String file:ls) {
System.out.println(file);
}
System.out.println(ls.size());
}
}
One more example of listing files and directories using Java 8 filter
public static void main(String[] args) {
System.out.println("Files!!");
try {
Files.walk(Paths.get("."))
.filter(Files::isRegularFile)
.filter(c ->
c.getFileName().toString().substring(c.getFileName().toString().length()-4).contains(".jpg")
||
c.getFileName().toString().substring(c.getFileName().toString().length()-5).contains(".jpeg")
)
.forEach(System.out::println);
} catch (IOException e) {
System.out.println("No jpeg or jpg files");
}
System.out.println("\nDirectories!!\n");
try {
Files.walk(Paths.get("."))
.filter(Files::isDirectory)
.forEach(System.out::println);
} catch (IOException e) {
System.out.println("No Jpeg files");
}
}
Test folder
I tested some method with 60,000 files in 284 folders on Windows 11:
public class App {
public static void main(String[] args) throws Exception {
Path path = Paths.get("E:\\书籍");
// 1.walkFileTree
long start1 = System.currentTimeMillis();
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
// if(pathMatcher.matches(file))
// files.add(file.toFile());
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
// System.out.println(dir.getFileName());
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path file, IOException e) {
return FileVisitResult.CONTINUE;
}
});
long end1 = System.currentTimeMillis();
// 2. newDirectoryStream
long start2 = System.currentTimeMillis();
search(path.toFile());
long end2 = System.currentTimeMillis();
// 3. listFiles
long start3 = System.currentTimeMillis();
getFileNames(path);
long end3 = System.currentTimeMillis();
System.out.println("\r执行耗时:" + (end1 - start1));
System.out.println("\r执行耗时:" + (end2 - start2));
System.out.println("\r执行耗时:" + (end3 - start3));
}
private static void getFileNames(Path dir) {
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path path : stream) {
if(Files.isDirectory(path)) {
getFileNames(path);
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
public static void search(File file) {
Queue<File> q = new LinkedList<>();
q.offer(file);
while (!q.isEmpty()) {
try {
for (File childfile : q.poll().listFiles()) {
// System.out.println(childfile.getName());
if (childfile.isDirectory()) {
q.offer(childfile);
}
}
} catch (Exception e) {
}
}
}
}
Result (milliseconds):
walkFileTree
listFiles
newDirectoryStream
68
451
493
64
464
482
61
478
457
67
477
488
59
474
466
Known performance issues:
From Kevin Day's answer:
If you profile your algorithm above, you'll find that the bulk of the time is spent in the pesky isDirectory() call - that's because you are incurring a round trip for every single call to isDirectory().
listfiles() will create new File Object for every entry
In Guava you don't have to wait for a Collection to be returned to you, but can actually iterate over the files. It is easy to imagine a IDoSomethingWithThisFile interface in the signature of the below function:
public static void collectFilesInDir(File dir) {
TreeTraverser<File> traverser = Files.fileTreeTraverser();
FluentIterable<File> filesInPostOrder = traverser.preOrderTraversal(dir);
for (File f: filesInPostOrder)
System.out.printf("File: %s\n", f.getPath());
}
TreeTraverser also allows you to between various traversal styles.
import java.io.*;
public class MultiFolderReading {
public void checkNoOfFiles (String filename) throws IOException {
File dir = new File(filename);
File files[] = dir.listFiles(); // Files array stores the list of files
for(int i=0; i<files.length; i++)
{
if(files[i].isFile()) // Check whether files[i] is file or directory
{
System.out.println("File::" + files[i].getName());
System.out.println();
}
else if(files[i].isDirectory())
{
System.out.println("Directory::" + files[i].getName());
System.out.println();
checkNoOfFiles(files[i].getAbsolutePath());
}
}
}
public static void main(String[] args) throws IOException {
MultiFolderReading mf = new MultiFolderReading();
String str = "E:\\file";
mf.checkNoOfFiles(str);
}
}
The more efficient way I found in dealing with millions of folders and files is to capture a directory listing through a DOS command in some file and parse it.
Once you have parsed the data then you can do analysis and compute statistics.

Recursively list files in Java

How do I recursively list all files under a directory in Java? Does the framework provide any utility?
I saw a lot of hacky implementations. But none from the framework or nio
Java 8 provides a nice stream to process all files in a tree.
try (Stream<Path> stream = Files.walk(Paths.get(path))) {
stream.filter(Files::isRegularFile)
.forEach(System.out::println);
}
This provides a natural way to traverse files. Since it's a stream you can do all nice stream operations on the result such as limit, grouping, mapping, exit early etc.
UPDATE: I might point out there is also Files.find which takes a BiPredicate that could be more efficient if you need to check file attributes.
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
Note that while the JavaDoc eludes that this method could be more efficient than Files.walk it is effectively identical, the difference in performance can be observed if you are also retrieving file attributes within your filter. In the end, if you need to filter on attributes use Files.find, otherwise use Files.walk, mostly because there are overloads and it's more convenient.
TESTS: As requested I've provided a performance comparison of many of the answers. Check out the Github project which contains results and a test case.
FileUtils have iterateFiles and listFiles methods. Give them a try. (from commons-io)
Edit: You can check here for a benchmark of different approaches. It seems that the commons-io approach is slow, so pick some of the faster ones from here (if it matters)
// Ready to run
import java.io.File;
public class Filewalker {
public void walk( String path ) {
File root = new File( path );
File[] list = root.listFiles();
if (list == null) return;
for ( File f : list ) {
if ( f.isDirectory() ) {
walk( f.getAbsolutePath() );
System.out.println( "Dir:" + f.getAbsoluteFile() );
}
else {
System.out.println( "File:" + f.getAbsoluteFile() );
}
}
}
public static void main(String[] args) {
Filewalker fw = new Filewalker();
fw.walk("c:\\" );
}
}
Java 7 will have has Files.walkFileTree:
If you provide a starting point and a file visitor, it will invoke various methods on the file visitor as it walks through the file in the file tree. We expect people to use this if they are developing a recursive copy, a recursive move, a recursive delete, or a recursive operation that sets permissions or performs another operation on each of the files.
There is now an entire Oracle tutorial on this question.
No external libraries needed.
Returns a Collection so you can do whatever you want with it after the call.
public static Collection<File> listFileTree(File dir) {
Set<File> fileTree = new HashSet<File>();
if(dir==null||dir.listFiles()==null){
return fileTree;
}
for (File entry : dir.listFiles()) {
if (entry.isFile()) fileTree.add(entry);
else fileTree.addAll(listFileTree(entry));
}
return fileTree;
}
I would go with something like:
public void list(File file) {
System.out.println(file.getName());
File[] children = file.listFiles();
for (File child : children) {
list(child);
}
}
The System.out.println is just there to indicate to do something with the file. there is no need to differentiate between files and directories, since a normal file will simply have zero children.
I prefer using a queue over recursion for this kind of simple traversion:
List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
for (File f : dirs.poll().listFiles()) {
if (f.isDirectory()) {
dirs.add(f);
} else if (f.isFile()) {
allFiles.add(f);
}
}
}
just write it yourself using simple recursion:
public List<File> addFiles(List<File> files, File dir)
{
if (files == null)
files = new LinkedList<File>();
if (!dir.isDirectory())
{
files.add(dir);
return files;
}
for (File file : dir.listFiles())
addFiles(files, file);
return files;
}
With Java 7 you can use the following class:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class MyFileIterator extends SimpleFileVisitor<Path>
{
public MyFileIterator(String path) throws Exception
{
Files.walkFileTree(Paths.get(path), this);
}
#Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attributes) throws IOException
{
System.out.println("File: " + file);
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attributes) throws IOException
{
System.out.println("Dir: " + dir);
return FileVisitResult.CONTINUE;
}
}
This code is ready to run
public static void main(String... args) {
File[] files = new File("D:/").listFiles();
if (files != null)
getFiles(files);
}
public static void getFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
getFiles(file.listFiles());
} else {
System.out.println("File: " + file);
}
}
}
I think this should do the work:
File dir = new File(dirname);
String[] files = dir.list();
This way you have files and dirs. Now use recursion and do the same for dirs (File class has isDirectory() method).
In Java 8, we can now use the Files utility to walk a file tree. Very simple.
Files.walk(root.toPath())
.filter(path -> !Files.isDirectory(path))
.forEach(path -> System.out.println(path));
Apart from the recursive traversal one can use a Visitor based approach as well.
Below code is uses Visitor based approach for the traversal.It is expected that the input to the program is the root directory to traverse.
public interface Visitor {
void visit(DirElement d);
void visit(FileElement f);
}
public abstract class Element {
protected File rootPath;
abstract void accept(Visitor v);
#Override
public String toString() {
return rootPath.getAbsolutePath();
}
}
public class FileElement extends Element {
FileElement(final String path) {
rootPath = new File(path);
}
#Override
void accept(final Visitor v) {
v.visit(this);
}
}
public class DirElement extends Element implements Iterable<Element> {
private final List<Element> elemList;
DirElement(final String path) {
elemList = new ArrayList<Element>();
rootPath = new File(path);
for (File f : rootPath.listFiles()) {
if (f.isDirectory()) {
elemList.add(new DirElement(f.getAbsolutePath()));
} else if (f.isFile()) {
elemList.add(new FileElement(f.getAbsolutePath()));
}
}
}
#Override
void accept(final Visitor v) {
v.visit(this);
}
public Iterator<Element> iterator() {
return elemList.iterator();
}
}
public class ElementWalker {
private final String rootDir;
ElementWalker(final String dir) {
rootDir = dir;
}
private void traverse() {
Element d = new DirElement(rootDir);
d.accept(new Walker());
}
public static void main(final String[] args) {
ElementWalker t = new ElementWalker("C:\\temp");
t.traverse();
}
private class Walker implements Visitor {
public void visit(final DirElement d) {
System.out.println(d);
for(Element e:d) {
e.accept(this);
}
}
public void visit(final FileElement f) {
System.out.println(f);
}
}
}
You can use below code to get a list of files of specific folder or directory recursively.
public static void main(String args[]) {
recusiveList("D:");
}
public static void recursiveList(String path) {
File f = new File(path);
File[] fl = f.listFiles();
for (int i = 0; i < fl.length; i++) {
if (fl[i].isDirectory() && !fl[i].isHidden()) {
System.out.println(fl[i].getAbsolutePath());
recusiveList(fl[i].getAbsolutePath());
} else {
System.out.println(fl[i].getName());
}
}
}
I came up with this for printing all the files/file names recursively.
private static void printAllFiles(String filePath,File folder) {
if(filePath==null) {
return;
}
File[] files = folder.listFiles();
for(File element : files) {
if(element.isDirectory()) {
printAllFiles(filePath,element);
} else {
System.out.println(" FileName "+ element.getName());
}
}
}
Lists all files with provided extensions,with option to scan
subfolders (recursive)
public static ArrayList<File> listFileTree(File dir,boolean recursive) {
if (null == dir || !dir.isDirectory()) {
return new ArrayList<>();
}
final Set<File> fileTree = new HashSet<File>();
FileFilter fileFilter = new FileFilter() {
private final String[] acceptedExtensions = new String[]{"jpg", "png", "webp", "jpeg"};
#Override
public boolean accept(File file) {
if (file.isDirectory()) {
return true;
}
for (String extension : acceptedExtensions) {
if (file.getName().toLowerCase().endsWith(extension)) {
return true;
}
}
return false;
}
};
File[] listed = dir.listFiles(fileFilter);
if(listed!=null){
for (File entry : listed) {
if (entry.isFile()) {
fileTree.add(entry);
} else if(recursive){
fileTree.addAll(listFileTree(entry,true));
}
}
}
return new ArrayList<>(fileTree);
}
List<Path> filePaths = Files
.find(Paths.get(dir), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile() || fileAttr.isDirectory())
.collect(Collectors.toList());
filePaths will have files and folder list which can be iterated and proceed further.
Non-recursive BFS with a single list (particular example is searching for *.eml files):
final FileFilter filter = new FileFilter() {
#Override
public boolean accept(File file) {
return file.isDirectory() || file.getName().endsWith(".eml");
}
};
// BFS recursive search
List<File> queue = new LinkedList<File>();
queue.addAll(Arrays.asList(dir.listFiles(filter)));
for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) {
File file = itr.next();
if (file.isDirectory()) {
itr.remove();
for (File f: file.listFiles(filter)) itr.add(f);
}
}
My version (of course I could have used the built in walk in Java 8 ;-) ):
public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) {
ArrayList<File> collected = new ArrayList<>();
walk(rootDir, predicate, collected);
return collected;
}
private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) {
Stream.of(listOnlyWhenDirectory(dir))
.forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction)));
}
private static File[] listOnlyWhenDirectory(File dir) {
return dir.isDirectory() ? dir.listFiles() : new File[]{};
}
private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) {
if (filterFunction.test(toAdd)) {
files.add(toAdd);
}
return files;
}
Here a simple but perfectly working solution using recursion:
public static List<Path> listFiles(String rootDirectory)
{
List<Path> files = new ArrayList<>();
listFiles(rootDirectory, files);
return files;
}
private static void listFiles(String path, List<Path> collectedFiles)
{
File root = new File(path);
File[] files = root.listFiles();
if (files == null)
{
return;
}
for (File file : files)
{
if (file.isDirectory())
{
listFiles(file.getAbsolutePath(), collectedFiles);
} else
{
collectedFiles.add(file.toPath());
}
}
}
private void fillFilesRecursively(File file, List<File> resultFiles) {
if (file.isFile()) {
resultFiles.add(file);
} else {
for (File child : file.listFiles()) {
fillFilesRecursively(child, resultFiles);
}
}
}
Kotlin has FileTreeWalk for this purpose. For example:
dataDir.walkTopDown().filter { !it.isDirectory }.joinToString("\n") {
"${it.toRelativeString(dataDir)}: ${it.length()}"
}
Will produce a text list of all the non-directory files under a given root, one file per line with the path relative to the root and length.
The accepted answer is great, however it breaks down when you want to do IO inside the lambda.
Here is what you can do if your action declares IOExceptions.
You can treat the filtered stream as an Iterable, and then do your action in a regular for-each loop. This way, you don't have to handle exceptions inside a lambda.
try (Stream<Path> pathStream = Files.walk(Paths.get(path))
.filter(Files::isRegularFile)) {
for (Path file : (Iterable<Path>) pathStream::iterator) {
// something that throws IOException
Files.copy(file, System.out);
}
}
Found that trick here: https://stackoverflow.com/a/32668807/1207791
Another way you can do even if someone already provide Java 8 walk.
This one will provide you all files recursively
private Stream<File> files(File file) {
return file.isDirectory()
? Arrays.stream(file.listFiles()).flatMap(this::files)
: Stream.of(file);
}
public static String getExten(String path) {
int i = path.lastIndexOf('.');
if (i > 0) {
return path.substring(i);
}
else return "";
}
public static List<String> GetAllFiles(String path, List<String>fileList){
File file = new File(path);
File[] files = file.listFiles();
for(File folder:files) {
if(extensions.contains(getExten(folder.getPath()))) {
fileList.add(folder.getPath());
}
}
File[] direcs = file.listFiles(File::isDirectory);
for(File dir:direcs) {
GetAllFiles(dir.getPath(),fileList);
}
return fileList;
}
This is a simple recursive function that should give you all the files. extensions is a list of string that contains only those extensions which are accepted. Example extensions = [".txt",".docx"] etc.
The accepted answer is poor because it can result in a resource leak.
Files.walk is backed by DirectoryStreams.
The returned stream encapsulates one or more DirectoryStreams. If timely disposal of file system resources is required, the try-with-resources construct should be used to ensure that the stream's close method is invoked after the stream operations are completed. Operating on a closed stream will result in an IllegalStateException.
A DirectoryStream must be closed as specified in it's javadoc:
A DirectoryStream is opened upon creation and is closed by invoking the close method. Closing a directory stream releases any resources associated with the stream. Failure to close the stream may result in a resource leak. The try-with-resources statement provides a useful construct to ensure that the stream is closed:
Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry: stream) {
...
}
}
As a result, the true answer is:
try (Stream<Path> stream = Files.walk(Paths.get(path))) {
// Do something with the stream.
stream.filter(Files::isRegularFile)
.forEach(System.out::println);
}
Example outputs *.csv files in directory recursive searching Subdirectories using Files.find() from java.nio:
String path = "C:/Daten/ibiss/ferret/";
logger.debug("Path:" + path);
try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) {
List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList());
for (String t : someThingNew) {
t.toString();
logger.debug("Filename:" + t);
}
}
Posting this example, as I had trouble understanding howto pass the filename parameter in the #1 example given by Bryan, using foreach on Stream-result -
Hope this helps.
base on #Michael answer, add check whether listFiles return null
static Stream<File> files(File file) {
return file.isDirectory()
? Optional.ofNullable(file.listFiles()).map(Stream::of).orElseGet(Stream::empty).flatMap(MainActivity::files)
: Stream.of(file);
}
or use Lightweight-Stream-API, which support Android5 & Android6
static Stream<File> files(File f) {
return f.isDirectory() ? Stream.ofNullable(f.listFiles()).flatMap(MainActivity::files) : Stream.of(f);
}
Based on stacker answer. Here is a solution working in JSP without any external libraries so you can put it almost anywhere on your server:
<!DOCTYPE html>
<%# page session="false" %>
<%# page import="java.util.*" %>
<%# page import="java.io.*" %>
<%# page contentType="text/html; charset=UTF-8" %>
<%!
public List<String> files = new ArrayList<String>();
/**
Fills files array with all sub-files.
*/
public void walk( File root ) {
File[] list = root.listFiles();
if (list == null) return;
for ( File f : list ) {
if ( f.isDirectory() ) {
walk( f );
}
else {
files.add(f.getAbsolutePath());
}
}
}
%>
<%
files.clear();
File jsp = new File(request.getRealPath(request.getServletPath()));
File dir = jsp.getParentFile();
walk(dir);
String prefixPath = dir.getAbsolutePath() + "/";
%>
Then you just do something like:
<ul>
<% for (String file : files) { %>
<% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
<li><%=file.replace(prefixPath, "")%></li>
<% } %>
<% } %>
</ul>
import java.io.File;
public class Main {
public static void main(String[] args) {
loopFiles(new File("C:\\Users\\serge.klimkovitch\\Documents"));
}
private static void loopFiles(File element) {
if (element.isDirectory()) {
for (File currentFile : element.listFiles()) {
loopFiles(currentFile);
System.out.println(currentFile);
}
}
}
}

Categories