how to scan multiple directory using java multi threading - java

The problem statement is, you have to list the name of the files from the given directory, you have given one directory structure which has some subdirectory and some file in them.
I did some part of the code but it is not working can you please help me what is the correct way of doing it.
code
public class Test {
public static void main(String[] args) {
RunableExample run = new RunableExample();
Thread th = new Thread(run, "thread1");
String directoryName = "C:\\Users\\GUR35893\\Desktop\\CleanupMTM";
File directory = new File(directoryName);
File[] fList = directory.listFiles();
RunableExample.MyList = new ArrayList<File>();
for (File file : fList) {
RunableExample.MyList.add(file);
}
try {
th.start();
} catch (Exception e) {
}
}
}
public class RunableExample implements Runnable {
public static List<File> MyList;
int count = 0;
File filepath;
public void run() {
try {
while (count < MyList.size()) {
System.out.println(Thread.currentThread().getName() + ">>>>"
+ MyList.size() + " >>>>> " + count);
filepath = MyList.get(count);
if (filepath != null && filepath.isFile()) {
System.out.println(Thread.currentThread().getName() + " >>"
+ filepath.getAbsolutePath());
} else {
synchronized (this) {
if (filepath != null) {
// System.out.println("Else");
RunableExample run3 = new RunableExample();
Thread th3 = new Thread(run3, "thread" + count);
File[] fList = filepath.listFiles();
// System.out.println("Else1");
for (File file : fList) {
MyList.add(file);
}
th3.start();
}
}
}
count++;
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
}
}

If you have a directory (including sub-directories) and you want list all files.
The simplest yet effective approach would be iterate through a directory, there will be just 2 options either its a file or its a directory.
If it's a file, simply name it, don't spawn a new thread for it.
If it's a directory, spawn a new thread and re-use the same code for traversing the files or sub-directories in that directory in the newly spawned thread.
If you could give a sample output then maybe we can help further. But till then, I don't see any use of synchronization in the code.

Implementation of #Himanshu Answer.
import java.io.File;
class Lister extends Thread{
String basepath;
Lister(String basepath){
this.basepath = basepath;
}
#Override
public void run(){
File rootDir = new File(basepath);
for(File f : rootDir.listFiles()){
if(f.isDirectory())
new Lister(f.toString()).start();
else
System.out.println(f);
}
}
}
class Main {
public static void main(String[] args) {
new Lister("/").start();
}
}
This code works, but make sure it don't memory overflow for huge directory trees. For that you can add extra checks to spawn only directory you need.

Related

How to apply multithreading in java to find a word in a directory(main directory and the word given) and recursively its subdirectories

I am quite new on Stack Overflow and a beginner in Java so please forgive me if I have asked this question in an improper way.
PROBLEM
I have an assignment which tells me to make use of multi-threading to search files for a given word, which might be present in any file of type .txt and .html, on any-level in the given directory (So basically the entire directory). The absolute file path of the file has to be displayed on the console if the file contains the given word.
WHAT HAVE I TRIED
So I thought of dividing the task into 2 sections, Searching and Multithreading respectively,
I was able to get the Searching part( File_search.java ). This file has given satisfactory results by searching through the directory and finding all the files in it for the given word.
File_search.java
public class File_search{
String fin_output = "";
public String searchInTextFiles(File dir,String search_word) {
File[] a = dir.listFiles();
for(File f : a){
if(f.isDirectory()) {
searchInTextFiles(f,search_word);
}
else if(f.getName().endsWith(".txt") || f.getName().endsWith(".html") || f.getName().endsWith(".htm") ) {
try {
searchInFile(f,search_word);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
return fin_output;
}
public void searchInFile(File f,String search_word) throws FileNotFoundException {
final Scanner sc = new Scanner(f);
while(sc.hasNextLine()) {
final String lineFromFile = sc.nextLine();
if(lineFromFile.contains(search_word)) {
fin_output += "FILE : "+f.getAbsolutePath().toString()+"\n";
}
}
}
Now, I want to be able to use multiple threads to execute the task File_search.java using ThreadPoolExecuter service. I'm not sure If I can do it using Runnable ,Callable or by using a Thread class or by any other method?
Can you please help me with the code to do the multi-threading part? Thanks :)
I agree to the comment of #chrylis -cautiouslyoptimistic, but for the purpose of understanding below will help you.
One simpler approach could be to do the traversal of directories in the main Thread, I mean the logic which you have added in function searchInTextFiles and do the searching logic as you did in function searchInFile in a Threadpool of size let's say 10.
Below sample code will help you to understand it better.
public class Traverser {
private List<Future<String>> futureList = new ArrayList<Future<String>>();
private ExecutorService executorService;
public Traverser() {
executorService = Executors.newFixedThreadPool(10);
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("Started");
long start = System.currentTimeMillis();
Traverser traverser = new Traverser();
traverser.searchInTextFiles(new File("Some Directory Path"), "Some Text");
for (Future<String> future : traverser.futureList) {
System.out.println(future.get());
}
traverser.executorService.shutdown();
while(!traverser.executorService.isTerminated()) {
System.out.println("Not terminated yet, sleeping");
Thread.sleep(1000);
}
long end = System.currentTimeMillis();
System.out.println("Time taken :" + (end - start));
}
public void searchInTextFiles(File dir,String searchWord) {
File[] filesList = dir.listFiles();
for(File file : filesList){
if(file.isDirectory()) {
searchInTextFiles(file,searchWord);
}
else if(file.getName().endsWith(".txt") || file.getName().endsWith(".html") || file.getName().endsWith(".htm") ) {
try {
futureList.add(executorService.submit(new SearcherTask(file,searchWord)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}}
public class SearcherTask implements Callable<String> {
private File inputFile;
private String searchWord;
public SearcherTask(File inputFile, String searchWord) {
this.inputFile = inputFile;
this.searchWord = searchWord;
}
#Override
public String call() throws Exception {
StringBuilder result = new StringBuilder();
Scanner sc = null;
try {
sc = new Scanner(inputFile);
while (sc.hasNextLine()) {
final String lineFromFile = sc.nextLine();
if (lineFromFile.contains(searchWord)) {
result.append("FILE : " + inputFile.getAbsolutePath().toString() + "\n");
}
}
} catch (Exception e) {
//log error
throw e;
} finally {
sc.close();
}
return result.toString();
}}

How to display in the main thread an integer incremented by the last started thread?

I wrote a little program which allows the user to find a file in a directory. The function is recursive and each crossed-directory is handled by a new thread. An integer, which counts the number of crossed directories, is incremented by each thread.
When the file is found, all these threads are interrupted, except the main-thread.
I want to display this integer in my thread-main, when the file is found but I don't understand how I could do this. Should I use join in Launcher ?
Here's the source. Thank you in advance !
FILE : LAUNCHER
public class Launcher {
public static void main(String args[]) {
try {
// Find's launch
Find find = new Find("tests.txt", "C:/Users/xxx/google_drive");
find.start();
// HERE : SHOULD I USE JOIN() ????
System.out.println("Number of crossed-directories " + Find.number_of_dirs);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
FILE : FIND
public class Find extends Thread {
private static ArrayList<Find> all_threads = new ArrayList<Find>();
private String file, dir;
protected static int number_of_dirs;
public Find(String file, String dir) {
this.file = file;
this.dir = dir;
synchronized (Find.class) {
Find.all_threads.add(this);
Find.incrementNumberOfDirs();
}
}
private static synchronized void incrementNumberOfDirs() {
Find.number_of_dirs++;
}
public void run() {
this.search(this.dir);
}
public void search(String file_path) {
File file = new File(file_path);
if(file.isDirectory()) {
System.out.println("Searching in the directory... " + file.getAbsolutePath());
for(File found_file : file.listFiles()) {
if(Find.interrupted()) {
synchronized (Find.class) {
Find.all_threads.remove(this);
}
return;
}
if(found_file.isDirectory()) {
Find find = new Find(this.file, found_file.getAbsolutePath());
find.start();
} else {
if(this.file.equals(found_file.getName())) {
Find.all_threads.forEach(thread -> thread.interrupt());
System.out.println("File was found here : " + found_file.getAbsolutePath() + " !");
}
}
}
}
}
}

How to find sub-directories in a directory/folder?

I'm looking for a way to get all the names of directories in a given directory, but not files.
For example, let's say I have a folder called Parent, and inside that I have 3 folders: Child1 Child2 and Child3.
I want to get the names of the folders, but don't care about the contents, or the names of subfolders inside Child1, Child2, etc.
Is there a simple way to do this?
If you are on java 7, you might wanna try using the support provided in
package java.nio.file
If your directory has many entries, it will be able to start listing them without reading them all into memory first. read more in the javadoc: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#newDirectoryStream(java.nio.file.Path,%20java.lang.String)
Here is also that example adapted to your needs:
public static void main(String[] args) {
DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
#Override
public boolean accept(Path file) throws IOException {
return (Files.isDirectory(file));
}
};
Path dir = FileSystems.getDefault().getPath("c:/");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
for (Path path : stream) {
// Iterate over the paths in the directory and print filenames
System.out.println(path.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
}
You can use String[] directories = file.list() to list all file names,
then use loop to check each sub-files and use file.isDirectory() function to get subdirectories.
For example:
File file = new File("C:\\Windows");
String[] names = file.list();
for(String name : names)
{
if (new File("C:\\Windows\\" + name).isDirectory())
{
System.out.println(name);
}
}
public static void displayDirectoryContents(File dir) {
try {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
System.out.println("Directory Name==>:" + file.getCanonicalPath());
displayDirectoryContents(file);
} else {
System.out.println("file Not Acess===>" + file.getCanonicalPath());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
====inside class/Method provide File=URL ======
File currentDir = new File("/home/akshya/NetBeansProjects/");
displayDirectoryContents(currentDir);
}

Deleting files in Android

I have a directory that contains a lot of files. I want to delete the entire directory as well as all the files in it.
I want my code to wait until every File in that directory (including the directory itself) is deleted before the next command is executed.
How do i wait?
My code is
public void wipeMemoryCard()
{
File deleteMatchingFile = new File(Environment
.getExternalStorageDirectory().toString());
try {
filenames = deleteMatchingFile.listFiles();
if (filenames != null && filenames.length > 0)
{
content = true;
for (File tempFile : filenames)
{
if (tempFile.isDirectory())
{
wipeDirectory(tempFile.toString());
tempFile.delete();
}
else
{
File file = new File(tempFile.getAbsolutePath());
file.delete();
}
}
}
else
{
deleteMatchingFile.delete();
Toast("No files to Delete");
}
}
catch (Exception e)
{
e.printStackTrace();
}
if(content == true)
{
if (filenames == null && filenames.length == 0)
{
Toast("Files Deleted");
}
}
}
private static void wipeDirectory(String name) {
File directoryFile = new File(name);
File[] filenames = directoryFile.listFiles();
if (filenames != null && filenames.length > 0)
{
for (File tempFile : filenames)
{
if (tempFile.isDirectory())
{
wipeDirectory(tempFile.toString());
tempFile.delete();
}
else
{
File file = new File(tempFile.getAbsolutePath());
file.delete();
}
}
} else
{
directoryFile.delete();
}
}
You should not run this on the UI thread. If the file deletion takes too long, the system will pop up an "Application Not Responding" error. You can do this with an AsyncTask. The documentation shows a simple way to use this to pop up a "please wait" dialog, do the time-consuming work in the background, and then dismiss the dialog.
P.S. Your method name is kind of scary! :)
You Should user Handler for this so when all files gets deleted it will send message to handler to the next task that you want to perform .
see this link for handler..
http://www.tutorialforandroid.com/2009/01/using-handler-in-android.html
Hope you are asking about this ....
public static void DeleteRecursive(String filename) {
File file = new File(filename);
if (!file.exists())
return;
if (!file.isDirectory()) {
file.delete();
return;
}
String[] files = file.list();
for (int i = 0; i < files.length; i++) {
DeleteRecursive(filename + "/" + files[i]);
}
file.delete();
}

How to display the contents of a directory

I need to write a recursive algorithm to display the contents of a directory in a computer's file system but I am very new to Java. Does anyone have any code or a good tutorial on how to access a directory in a file system with Java??
You can use the JFileChooser class, check this example.
Optionally you can also execute native commands like DIR , lsusing java , here is an example
This took me way too long to write and test, but here's something that should work.
Note: You can pass in either a string or file.
Note 2: This is a naive implementation. Not only is it single-threaded, but it does not check to see if files are links, and could get stuck in an endless loop due to this.
Note 3: The lines immediately after comments can be replaced with your own implementation.
import java.io.*;
public class DirectoryRecurser {
public static void parseFile(String filePath) throws FileNotFoundException {
File file = new File(filePath);
if (file.exists()) {
parseFile(file);
} else {
throw new FileNotFoundException(file.getPath());
}
}
public static void parseFile(File file) throws FileNotFoundException {
if (file.isDirectory()) {
for(File child : file.listFiles()) {
parseFile(child);
}
} else if (file.exists()) {
// Process file here
System.out.println(file.getPath());
} else {
throw new FileNotFoundException(file.getPath());
}
}
}
Which could then be called something like this (using a Windows path, because this Workstation is using Windows):
public static void main(String[] args) {
try {
DirectoryRecurser.parseFile("D:\\raisin");
} catch (FileNotFoundException e) {
// Error handling here
System.out.println("File not found: " + e.getMessage());
}
}
In my case, this prints out:
File not found: D:\raisin
because said directory is just one I made up. Otherwise, it prints out the path to each file.
Check out Apache Commons VFS: http://commons.apache.org/vfs/
Sample:
// Locate the Jar file
FileSystemManager fsManager = VFS.getManager();
FileObject jarFile = fsManager.resolveFile( "jar:lib/aJarFile.jar" );
// List the children of the Jar file
FileObject[] children = jarFile.getChildren();
System.out.println( "Children of " + jarFile.getName().getURI() );
for ( int i = 0; i < children.length; i++ )
{
System.out.println( children[ i ].getName().getBaseName() );
}
If you need to access files on a network drive, check out JCIFS: http://jcifs.samba.org/
check this out buddy
http://java2s.com/Code/Java/File-Input-Output/Traversingallfilesanddirectoriesunderdir.htm
public class Main {
public static void main(String[] argv) throws Exception {
}
public static void visitAllDirsAndFiles(File dir) {
System.out.println(dir);
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
visitAllDirsAndFiles(new File(dir, children[i]));
}
}
}
}
For each file you need to check if it is a directory. If it is, you need to recurse. Here is some untested code, which should help:
public void listFiles(File f){
System.out.println(f.getAbsolutePath());
if(f.isDirectory()){
for (File i : f.listFiles()){
listFiles(i);
}
}
}

Categories