Exhaustive Nested Directory Search in Java - java

I was working on writing a recursive program which will take a path as input. Then it will search exhaustively all files and folders under it no matter in which depth the files and folders are in.
I've already written a java program given below :
void RecursiveFileSearch(File f, String d) {
int i;
String s[] = f.list();
for (i = 0; i < s.length; i++) {
File fs = new File(d + "/" + s[i]);
if (fs.isDirectory()) {
System.out.println("#DIRECTORY :"+s[i]);
d += "/" + s[i];
RecursiveFileSearch(fs, d);
} else {
System.out.println("#FILE : "+s[i]);
}
}
}
This function is called from outside like :
String sourceDirectoryPath = "D:";
File sourceFile = new File(sourceDirectoryPath);
RecursiveFileSearch(sourceFile,sourceDirectoryPath);
But the problem is that searches only the files and folders under the source directory only. It doesn't go into further depth.
Am I missing something?

Why don't you just use the APIs the JDK has for you?
With Java 8, it is as simple as:
try (
final Stream<Path> stream = Files.walk(baseDir);
) {
stream.forEach(path -> System.out.printf("%s: %s\n",
(Files.isDirectory(path) ? "DIRECTORY": "FILE"), path));
}

The problem is that the String variable d gets changed in each recursive call to the method, each time appending a directory name to the previous directory. You can solve this by defining a new String variable instead of re-using the same one:
void RecursiveFileSearch(File f, String d) {
int i;
String s[] = f.list();
for (i = 0; i < s.length; i++) {
File fs = new File(d + "/" + s[i]);
if (fs.isDirectory()) {
System.out.println("#DIRECTORY :"+s[i]);
String d2 = d + "/" + s[i];
RecursiveFileSearch(fs, d2);
} else {
System.out.println("#FILE : "+s[i]);
}
}
}

I dont know why you make thes work arround with Strings. Use "getAbsoluteFile" to geht the Path as a String befor you print it to the console and work only on File Objects in the programming logic. That will make your code mutch cleaner.
void RecursiveFileSearch(File f) {
File[] list = f.listFiles();
for (File elem : list) {
if (elem.isDirectory()) {
System.out.println("#DIRECTORY:"+elem.getAbsoluteFile());
RecursiveFileSearch(x);
} else {
System.out.println("#FILE : "+elem.getAbsoluteFile());
}
}
}
Edit: Deleted the now useless declaration if i.

This should work:
void RecursiveFileSearch(File f, String d) {
int i;
String s[] = f.list();
for (i = 0; i < s.length; i++) {
File fs = new File(d + "/" + s[i]);
if (fs.isDirectory()) {
System.out.println("#DIRECTORY :"+s[i]);
RecursiveFileSearch(fs, d + "/" + s[i]);
} else {
System.out.println("#FILE : "+s[i]);
}
}
}

Related

How can we solve this error in comparing two folders and storing those files with same name in an array?

I am a beginner in Java and I wanted to create a program that compares two folders and can store the files with same name in an array. I want to access this array in another class to display the name of files.
public int fileCompare(String path1, String path2) {
int i, j, k = 0;
flag = 0;
File file1 = new File(path1);
File file2 = new File(path2);
File[] array_file1 = file1.listFiles();
File[] array_file2 = file2.listFiles();
int largerSize = array_file1.length > array_file2.length ? array_file1.length : array_file2.length;
File[] equalFiles1 = new File[largerSize];
File[] equalFiles2 = new File[largerSize];
for (i = 0; i < array_file1.length; i++) {
String n1 = array_file1[i].getName();
for (j = 0; j < array_file2.length; j++) {
String n2 = array_file2[j].getName();
if (n1.equals(n2)) {
flag++;
equalFiles1[k] = array_file1[i];
equalFiles2[k] = array_file2[j];
k++;
}
}
}
}
The above code contains the method for comparing two folders and returning the arrays. This array is then accessed using the below code.
for (File file : c.equalFiles1) { // c is the object of previous class
for (int i = 0; i < c.flag; i++) {
row1[i] = file.getName();
}
}
But the error was shown as
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
Index 0 out of bounds for length 0
the problem is in the second loop
for (j = 0; j < array_file2.length; j++) {
String n2 = array_file2[i].getName();
}
you put i instead of j hence when file1 length is greater than file2, the index got out of bound
and in demo2hack you init string row using c.flag
while c.flag is still 0
you should initialized your string row after calling c.compare file if you wanna use c.flag
The code below compiles and prints the elements of array row1. You can copy and paste in https://www.onlinegdb.com/online_c_compiler and select JAVA on the pulldown box, top right of screen. You still need to fix the logic to get meet the requirements
import java.io.*;
public class Main
{
public static final String DIR_PATH1 = "./"; // replace with dir path
public static final String DIR_PATH2 = "../../";
public static void main(String[] args) {
DemoHack1 c = new DemoHack1();
String folderpath1 = DIR_PATH1;
String folderpath2 = DIR_PATH1;
c.flag = c.fileCompare(folderpath1, folderpath2);
if (c.flag > 0) { // make sure to void creating an array of size zero
String[] row1= new String[c.flag];
for (File file : c.equalFiles1 ) {
for(int i=0; i < c.flag;i++){
row1[i]= file.getName() ;
}
}
for(String r : row1){
System.out.println("files in row>> "+ r ) ;
}
}
System.out.println("-----end -----");
}
}
class DemoHack1 {
public File[] equalFiles1;
public File[] equalFiles2;
int flag;
public int fileCompare(String path1, String path2) {
int k=0;
flag=0;
File file1 = new File(path1);
File file2 = new File(path2);
File[] array_file1=file1.listFiles();
File[] array_file2=file2.listFiles();
int size1 = array_file1.length>array_file2.length ? array_file1.length:array_file2.length;
equalFiles1 = new File[size1];
equalFiles2 = new File[size1];
for(int i=0; i< array_file1.length; i++){
String n1=array_file1[i].getName();
//System.out.println("n1>> " + n1); // use print stmt to check the values
for(int j=0; j <array_file2.length; j++){
String n2=array_file2[j].getName();
//System.out.println("n2>> " + n2);
if (n1.equals(n2)) {
flag++;
equalFiles1[k]= array_file1[i] ;
equalFiles2[k] = array_file2[j];
k++;
}
}
}
return flag;
}
}
Output:
files in row>> DemoHack1.class
files in row>> DemoHack1.class
files in row>> DemoHack1.class
files in row>> DemoHack1.class
files in row>> DemoHack1.class
-----end -----

Returning an Array incorrectly, overwriting all with the last item

I've seen some similar post but not the same issue I'm having. What I'm trying to do is calling a function that shows the name of the files numbered as
1- File1.txt,
2- File2.txt
..
This works as expected. The problem is that I need to return the path of those files in another Array. When I System.out.print(arrayRutasFicheros[j]) inside for, it shows all paths correctly. But when I try to access arrayRutasFicheros[j] from other functions. It just overwrites all the paths and just shows the last one.
public static String[] listarArchivos() throws IOException{
File[] listadoDeFiles = documento.listFiles();
File[] arrayFicheros = null;
String[] arrayRutasFicheros = null;
if(documento.exists() ) {
for (int k=0; k< listadoDeFiles.length ;k++) {
File ficheroRuta = listadoDeFiles[k];
File fichero = new File(documento.getPath() + sep+ ficheroRuta.getName());
if(fichero.isFile()==true) {
arrayFicheros =new File[] {fichero};
System.out.println( k + " - " + ficheroRuta.getName());
for(int j= 0; j<arrayFicheros.length; j++) {
arrayRutasFicheros = new String[] {arrayFicheros[j].getPath()};
//here it works and it display all the path
System.out.println(arrayRutasFicheros[j]);
}
}
}
}
return arrayRutasFicheros;
}
public static muestraUnArchivo() throws IOException {
String [] Fichero =listarArchivos();
for(int k=0; k<Fichero.length; k++) {
//here just the last one
System.out.print(Fichero[k]);
}
}
Expected:
-E:\Eclipse\Files\File1.txt
-E:\Eclipse\Files\File2.txt
-E:\Eclipse\Files\File3.txt
Output:
-E:\Eclipse\Files\File3.txt
Your array is recreated on every iteration of the loop, which is also on an array of length 1. You need a dynamic structure to store the string paths, because you don't know ahead of time how many there are. Also, you don't need to keep creating single element arrays; use a List<String>. Something like,
public static String[] listarArchivos() throws IOException {
List<String> al = new ArrayList<>();
if (documento.exists()) {
File[] listadoDeFiles = documento.listFiles();
for (File ficheroRuta : listadoDeFiles) {
File fichero = new File(documento.getPath()
+ sep + ficheroRuta.getName());
if (fichero.isFile()) {
al.add(fichero.getPath());
}
}
}
return al.toArray(new String[0]);
}
The following lines are not only unnecessary but also causing the issue which you are facing. The line, arrayRutasFicheros = new String[] {arrayFicheros[j].getPath()}; is resetting arrayRutasFicheros for each value of k and therefore you will get only the value assigned to it at the the last value of k.
if(fichero.isFile()==true) {
arrayFicheros =new File[] {fichero};
System.out.println( k + " - " + ficheroRuta.getName());
for(int j= 0; j<arrayFicheros.length; j++) {
arrayRutasFicheros = new String[] {arrayFicheros[j].getPath()};
//here it works and it display all the path
System.out.println(arrayRutasFicheros[j]);
}
}
Replace the above lines with the following code:
if(fichero.isFile()) {
arrayRutasFicheros[k] = fichero.getPath();
}
Following line set the last value when the for ends the iteration.
I hope you will understand the logic.
arrayRutasFicheros = new String[] {arrayFicheros[j].getPath()};
Please let me know if you have any confusion.
Happy coding.

Check or folders recursively, but skip a particular one

Ok, I have a pretty common function to check all files from a path (including sub-folders). In the given path I have multiple folders, like Folder1, Folder2, Folder3... Foldern, and I want to skip Folder2 for example. What is the best method to do that? Down below is my function.
public void loadFileRecursiv(String pathDir)
{
File fisier = new File(pathDir);
File[] listaFisiere = fisier.listFiles();
for(int i = 0; i < listaFisiere.length; i++)
{
if(listaFisiere[i].isDirectory())
{
loadFileRecursiv(pathDir + File.separatorChar + listaFisiere[i].getName());
}
else
{
String cuExtensie = listaFisiere[i].getName();
int pos = cuExtensie.lastIndexOf(".");
String nume = cuExtensie.substring(0, pos);
String acronimBanca = nume.split("_")[0];
String tipAct = nume.split("_")[1];
String dataActString = nume.split("_")[2];
SimpleDateFormat old = new SimpleDateFormat("dd-MM-yyyy");
SimpleDateFormat newPattern = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String dataFormatata = null;
try
{
dataFormatata = newPattern.format(old.parse(dataActString));
}
catch(ParseException e)
{
e.printStackTrace();
}
//String denBanca = inlocuireAcronim(acronimBanca);
processFolder(acronimBanca, acronimBanca);
insertData(listaFisiere[i], nume, acronimBanca, tipAct, dataFormatata);
System.out.println("AICI =========== " + pathDir + File.separatorChar + listaFisiere[i].getName());
moveFile(pathDir + File.separatorChar + listaFisiere[i].getName(), "/u02/ActeConstitutive/Mutate/");
}
}
}
I would advice you to use a Set containing the folders you want to skip.
// get the folders you want to avoid and add them to your set
File Folder2 = new File(pathName);
Set<File> folderToSkip = new HashSet<File>();
folderToSkip.add(Folder2);
// add as many other folders you want to avoid
And then in the for loop, you can check whether or not you want to go inside this folder
for(int i = 0; i < listaFisiere.length; i++){
if(!folderToSkip.contains(listaFisiere[i]){
// do your stuff...
}
}
Whilst your approach is recursive, the recursive part only applies to folder levels. You can skip over a loop operation via the
continue
keyword. Such as below:
for(int i = 0;i<5;i++){
if(i == 0){
continue;
}
System.out.println(i);
}
would skip over 0, the first operation, and output the following
1
2
3
4
Example here
This allows you to build a more modular loop, in my opinion it looks better than
for(int i = 0;i<5;i++){
if(i != 0){
System.out.println(i);
}
}
especially when nesting more conditionals or loops within, like so:
for(int i = 0;i<5;i++){
if(i != 0){
if(i != 0){
if(i != 0){
if(i != 0){
if(i != 0){
// stuff
}
}
}
}
}
}
Do it like this:
for(int i = 0; i < listaFisiere.length; i++)
{
if(listaFisiere[i].isDirectory())
{
if (!listaFisiere[i].getName().equalsIgnoreCase("Folder2"))
loadFileRecursiv(pathDir + File.separatorChar + listaFisiere[i].getName());
}
else
{
add an if statement at the first of method.
public void loadFileRecursiv(String pathDir)
{
if(new File(pathDir).isDirectory() && skip(pathDir))
return;
and make skip method which takes the path and checks that if you want to skip that folder or not; which returns a boolean. true means skip that.

Q&A system from corpus in java

I have a corpus that contains a short story with 5 "who", "what", "when", "where", "why" questions. I have used Stanford NLP API to separate the story into sentences which then the I get the lemma for each word in the sentence giving me the base word. I do the same with the questions. I have the story and the sentences saved in separate files from which I use WS4J to help me determine which sentence from the story can answer each question.
I am using this method that takes 2 Strings (question, and the possible) and compares them to each other and returns a value which its a possible answer to the question or not.
public int compSen(double prob, String sen1, String sen2) {
int cant = 0;
// String sen2c = remStopWords(sen2);
String[] sent1 = getWords(sen1);
String[] sent2 = getWords(sen2);
for (int s = 0; s < sent2.length - 1; s++) {
for (int m = s + 1; m < sent2.length; m++) {
if (sent2[s] != "" && sent2[s].equals(sent2[m])) {
sent2[m] = "";
}
}
}
for (int i = 0; i < sent1.length; i++) {
for (int j = 0; j < sent2.length; j++) {
if (sent2[j] != "") {
double res = compWord(sent1[i].trim(), sent2[j].trim());
if (res >= prob) {
// System.out.println(sent1[i] + " " + sent2[j]);
// System.out.println(res);
cant++;
}
}
}
}
return cant;
}
My other method which compares the words is like this:
public double compWord(String word1, String word2) {
ILexicalDatabase db = new NictWordNet();
WS4JConfiguration.getInstance().setMFS(true);
RelatednessCalculator rc = new Path(db);
// String word1 = "gender";
// String word2 = "sex";
List<POS[]> posPairs = rc.getPOSPairs();
double maxScore = -1D;
for (POS[] posPair : posPairs) {
List<Concept> synsets1 = (List<Concept>) db.getAllConcepts(word1, posPair[0].toString());
List<Concept> synsets2 = (List<Concept>) db.getAllConcepts(word2, posPair[1].toString());
for (Concept synset1 : synsets1) {
for (Concept synset2 : synsets2) {
Relatedness relatedness = rc.calcRelatednessOfSynset(synset1, synset2);
double score = relatedness.getScore();
if (score > maxScore) {
maxScore = score;
}
}
}
}
if (maxScore == -1D) {
maxScore = 0.0;
}
// System.out.println(word1);
// System.out.println(word2);
//
// System.out.println(maxScore);
// System.out.println("sim('" + word1 + "', '" + word2 + "') = " + maxScore);
return maxScore;
}
I was wondering if there is another way to better answer questions from a corpus given a story to analyze, since my method is very basic and I managed to answer almost 1-3 questions out of 20. To me this is really good. Any help, idea is appreciated.
You are testing for an empty string the wrong way. For example
if (sent2[j] != "") { ...
Unless the API you are using guarantees to canonicalize the strings it returns, that is unreliable. Java does not guarantee that all empty strings are the same object as "". The following are reliable ways to test if a string is empty:
if ("".equal(sent2[j])) { ... // works even for a null !!!
if (sent2[j].equals("") { ...
if (sent2[j].length() == 0) { ...
if (sent2[j].isEmpty()) { ... // Java 6 onwards
This may not be what it is causing the program to fail, but it is most likely an error.

How To Parse a URL in J2ME

I'm trying to extract the query's name-value pairs from a URL using J2ME, but it doesn't make it easy. J2ME doesn't have the java.net.URL class nor does String have a split method.
Is there a way to extract name-value pairs from a URL using J2ME? Any open source implementations would be welcome too.
I like kchau answer but i just changed the data structure from two arrays to one Hashtable. This will also help if the number of URL parameters is unknown.
String url = "http://www.so.com?name1=value1&name2=value2&name3=value3";
Hashtable values = new Hashtable();
int s = url.indexOf("?");
int e = 0;
while (s != -1) {
e = url.indexOf("=", s);
String name = url.substring(s + 1, e);
s = e + 1;
e = url.indexOf("&", s);
if (e < 0) {
values.put(name, url.substring(s, url.length()));
} else {
values.put(name, url.substring(s, e));
}
s = e;
}
for (Enumeration num = values.keys(); num.hasMoreElements();) {
String key = (String)num.nextElement();
System.out.println(key + " " + values.get(key));
}
Here's my stab at it, some similarity to David's answer.
String url = "http://www.stackoverflow.com?name1=value1&name2=value2&name3=value3";
String[] names = new String[10];
String[] values = new String[10];
int s = url.indexOf("?"); // Get start index of first name
int e = 0, idx = 0;
while (s != -1) {
e = url.indexOf("=", s); // Get end index of name string
names[idx] = url.substring(s+1, e);
s = e + 1; // Get start index of value string
e = url.indexOf("&", s); // Get index of next pair
if (e < 0) // Last pair
values[idx] = url.substring(s, url.length());
else // o.w. keep storing
values[idx] = url.substring(s, e);
s = e;
idx++;
}
for(int x = 0; x < 10; x++)
System.out.println(names[x] +" = "+ values[x]);
Tested it, and I think it works. Hope it helps, good luck.
Since the Java JDK is open-source, you could also borrow the java URL class from the main JDK and add it to your project. This would let you use the same implementation from Java SE:
http://www.docjar.com/html/api/java/net/URL.java.html
Off the top of my head, it'd go something like this (warning: untested):
String url = ...;
int s = url.indexOf("?") + 1;
while (s > 0) {
int e = url.indexOf("=", s);
String name = url.substring(s, e), value;
s = e + 1;
e = url.indexOf("&", s);
if (e < 0)
value = url.substring(s, e);
else
value = url.substring(s, e);
// process name, value
s = e;
}
Query strings can technically be separated by a semicolon instead of an ampersand, like name1=value1;name2=value2;..., although I've never seen it done in practice. If that's a concern for you, I'm sure you can fix up the code for it.
There's a J2ME implementation that doesn't have java.net.URL?
It's part of the Connected Device Configuration, Foundation Profile, Personal Basis Profile, and Personal Profile...
Edit: For the record, these are the CDC 1.1.2 links, but according to JSR36, CDC 1.0 also has a java.net.URL class.
Also, please note, that url params are URL-Encoded, so you may need to decode them first (how to do it is another question)
I get parameters in this way:
public String getUrlParam(String url, String param)
{
int startIndex = url.indexOf(""+param+"=");
if (startIndex == -1)
return null;
int length = (""+param+"=").length();
int endIndex = url.indexOf("&", startIndex+length);
if (endIndex == -1)
endIndex = url.length();
return URLDecode(url.substring(startIndex+length, endIndex));
}
A URL Encoder/Decoder is really simple and easy to write. You can also look up any open source HTML to WML transcoder code on the internet and modify it. Shouldnt be too hard.

Categories