I have the following code in hadoop and when it runs it produces the output of the mapper as the output of the reducer. The reducer basically does nothing. The 2 input files are in the form:
File A: Jan-1 #starwars,17115 (Each line is like this one.) VALUE is the number 17115.
File B: #starwars,2017/1/1 5696 (Each line is like this one.) VALUE is the number 5696.
Mapper class processes these file and outputs(only the bold letters):
JAN #STARWARS 17115/A where KEY: JAN #STARWARS
JAN #STARWARS 5696/B where KEY: JAN #STARWARS
The reducer is supposed to do the following:
All the same keys go to one reducer, correct me if i'm wrong i'm new to hadoop and each reducer splits the value to 2 parts : the key and the value
KEY: A, VALUE 17115
KEY: B, VALUE 5696
For the moment it should just adds all the values without caring if it's coming from A or B and writes(only bold):
JAN #STARWARS 22.811 (22.811 = 17115+5696)
So why does it write the mappers output without the reducer doing what it is supposed to do?
I din't set the num of reducer to zero.
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.MultipleInputs;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.Partitioner;
public class WordCount {
public static class TokenizerMapper
extends Mapper<Object, Text, Text, Text>{
//private final static IntWritable result = new IntWritable();
private Text word = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString(),"\n");
while (itr.hasMoreTokens()) {
String nextWord = itr.nextToken().toUpperCase();
//System.out.println("'"+nextWord+"'");
if(isFromPlatformB(nextWord)){
//Procedure for words of Platform B.
String[] split1 = nextWord.split("(,)|(/)|(\\s)");
String seriesTitle = split1[0];
String numOfMonth = split1[2];
String numOfDay = split1[3];
String number = split1[4];//VALUE
int monthInt = Integer.parseInt(numOfMonth);
String monthString;
switch (monthInt) {
case 1: monthString = "JAN";
break;
case 2: monthString = "FEB";
break;
case 3: monthString = "MAR";
break;
case 4: monthString = "APR";
break;
case 5: monthString = "MAY";
break;
case 6: monthString = "JUN";
break;
case 7: monthString = "JUL";
break;
case 8: monthString = "AUG";
break;
case 9: monthString = "SEP";
break;
case 10: monthString = "OCT";
break;
case 11: monthString = "NOV";
break;
case 12: monthString = "DEC";
break;
default: monthString = "ERROR";
break;
}
//result.set(numberInt);
word.set(monthString + " " + seriesTitle);
System.out.println("key: "+monthString + " " + seriesTitle + ", value: "+number+"/B");
context.write(word, new Text(number + "/B"));
//FORMAT : <KEY,VALUE/B>
}
else{
//Procedure for words of Platform A.
String[] split5 = nextWord.split("(-)|( )|(,)");
String month = split5[0];
String seriesTitle = split5[2];
String value2 = split5[3];//OUTVALUE
String finalWord = month + " " + seriesTitle;//OUTKEY KEY: <APR #WESTWORLD>
word.set(finalWord);
//result.set(valueInt);
System.out.println("key: "+finalWord + ", value: "+value2+"/A");
context.write(word, new Text(value2 + "/A"));
//FORMAT : <KEY,VALUE/A>
}
}
}
/*
*This method takes the next token and returns true if the token is taken from platform B file,
*Or it returns false if the token comes from platform A file.
*
*/
public boolean isFromPlatformB(String nextToken){
// B platform has the form of : "#WestWorld ,2017/1/2){
if(nextToken.charAt(0) == '#'){
return true;
}
return false;
}
}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,Text> {
//private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<Text> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (Text val : values) {
String valToString = val.toString();
String[] split = valToString.split("/");
//String keyOfValue;
String valueOfValue;
int intValueOfValue = 0;
// FORMAT : <KEY,VALUE/platform> [<KEY,VALUE>,VALUE = <key,value>]
// [0] [1]
if(split.length>1){
//keyOfValue = split[1];
valueOfValue = split[0];
//System.out.println(key);
//System.out.println(valueOfValue);
//System.out.println(keyOfValue);
intValueOfValue = Integer.parseInt(valueOfValue);
/*if(keyOfValue.equals("A")){//If value is from platform A
counterForPlatformA += intValueOfValue;
System.out.println("KEY = 'A' " + "VALUE :" +intValueOfValue);
System.out.println("counter A: "+ counterForPlatformA +"|| counter B: "+ counterForPlatformB + "||----||");
}
else if(keyOfValue.equals("B")){//If value is from platform B
counterForPlatformB += intValueOfValue;
System.out.println("KEY = 'B' " + "VALUE :" +intValueOfValue);
System.out.println("counter A: "+ counterForPlatformA +"|| counter B: "+ counterForPlatformB + "||----||");
}
else{
//ERROR
System.out.println("Not equal to A or B");
}*/
}
sum += intValueOfValue;
}
context.write(key, new Text(sum));
}
}
public static void main(String[] args) throws Exception{
if (args.length != 3 ){
System.err.println ("Usage :<inputlocation1> <inputlocation2> <outputlocation> >");
System.exit(0);
}
Configuration conf = new Configuration();
String[] files=new GenericOptionsParser(conf,args).getRemainingArgs();
Path input1=new Path(files[0]);
Path input2=new Path(files[1]);
Path output=new Path(files[2]);
//If OUTPUT already exists -> Delete it
FileSystem fs = FileSystem.get(conf);
if(fs.exists(output)){
fs.delete(output, true);
}
Job job = Job.getInstance(conf, "word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
MultipleInputs.addInputPath(job, input1, TextInputFormat.class);
MultipleInputs.addInputPath(job, input2, TextInputFormat.class);
FileOutputFormat.setOutputPath(job, output);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
It looks like your reducer takes in a pair of Text objects and outputs Text. If this is the case, it looks like you have a few problems:
In your main you have:
job.setOutputValueClass(IntWritable.class) which should probably be job.setOutputValueClass(Text.class)
You are also defining your reducer as:
public static class IntSumReducer extends Reducer<Text,IntWritable,Text,Text> it should be public static class IntSumReducer extends Reducer<Text,Text,Text,Text>
The reducer is receiving Text values, not IntWritables.
It was the combiner finally. If you set your reducer as your combiner too then you can't have different types between your mapper and reducer.
Related
I'm setting up a program to sort information including names, addresses, phone numbers, and emails. But there is no format for the user's input and I am having trouble splitting up the information. Any tips?
I've tried using a combination of if/else statements and I have to use a for loop to go through all the information.
This is what is given to me
String[] TheNeededData = new String[]{"Alexa Pope/P.O. Box 435 5461 Euismod Avenue1-182-963-3500 blandit.congue#utcursus.co.uk",
"Kylynn Allen/8402 Justo St.1-357-430-1865morbi.tristique#lectus.org","Moana Cannon 522-1918 Quisque Rd. 1-752-893-8123 enim.mi#idsapienCras.edu"};
This is what I tried
int count;
public TheData(String TheString)
{
int x = TheString.length();
for(int y = 0; y<x; y++)
{
String z = String.valueOf(TheString.charAt(y));
if(z.equals("/"))
System.out.println(TheString.substring(0,y));
else
{
if(count == 1)
if(z.equals(" "))
{
System.out.println(TheString.substring(0,y));
count++;
}
if(count == 0)
if(z.equals(" "))
{
count ++;
}
}
}
}
This was the output
Alexa Pope
Alexa Pope/P.O.
Kylynn Allen
Kylynn Allen/8402
Moana Cannon 522-1918
I expected to have the first few names be printed using a substring to the charAt("/"), then I tried to find the last name by identifying the first two spaces, but it printed more than just the names along with printing the names more than once.
As you do not know what is the data format I would try to iterate over some or all the entries and adjust patterns in the process.
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.stream.Collectors.toList;
public class Main {
private static final Pattern NAME_REGEX =
Pattern.compile("^([A-Z]+ [A-Z]+ ).*$", CASE_INSENSITIVE);
private static final Pattern EMAIL_ADDRESS_REGEX =
Pattern.compile("^.* ([A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}).*$", CASE_INSENSITIVE);
private static final Pattern PHONE_NUMBER_REGEX =
Pattern.compile("^.*(\\d-\\d{3}-\\d{3}-\\d{4}).*$", CASE_INSENSITIVE);
public static void main(String[] args) {
var data = new String[]{
"Alexa Pope/P.O. Box 435 5461 Euismod Avenue1-182-963-3500 blandit.congue#utcursus.co.uk",
"Kylynn Allen/8402 Justo St.1-357-430-1865morbi.tristique#lectus.org",
"Moana Cannon 522-1918 Quisque Rd. 1-752-893-8123 enim.mi#idsapienCras.edu"};
for (var entry : cleanUpData(data)) {
System.out.println("\n" + entry);
var name = findMatch(entry, NAME_REGEX).orElse("");
var phoneNumber = findMatch(entry, PHONE_NUMBER_REGEX).orElse("");
entry = entry.replace(phoneNumber, " ");
var emailAddress = findMatch(entry, EMAIL_ADDRESS_REGEX).orElse("");
System.out.println("Name: " + name);
System.out.println("Email: " + emailAddress);
System.out.println("Phone: " + phoneNumber);
}
}
private static List<String> cleanUpData(String[] data) {
return Arrays.stream(data).map(s -> s
.replace("/", " ")
.trim()
.replaceAll(" +", " ")
).collect(toList());
}
private static Optional<String> findMatch(String entry, Pattern pattern) {
Matcher matcher = pattern.matcher(entry);
if (!matcher.find()) {
return Optional.empty();
}
try {
return Optional.of(matcher.group(1));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
}
Output:
Alexa Pope P.O. Box 435 5461 Euismod Avenue1-182-963-3500 blandit.congue#utcursus.co.uk
Name: Alexa Pope
Email: blandit.congue#utcursus.co.uk
Phone: 1-182-963-3500
Kylynn Allen 8402 Justo St.1-357-430-1865morbi.tristique#lectus.org
Name: Kylynn Allen
Email: morbi.tristique#lectus.org
Phone: 1-357-430-1865
Moana Cannon 522-1918 Quisque Rd. 1-752-893-8123 enim.mi#idsapienCras.edu
Name: Moana Cannon
Email: enim.mi#idsapienCras.edu
Phone: 1-752-893-8123
I am making a program which can make singular words plural, however I am unsure how I would go about checking the exceptions in the string array I created. I know there are more exceptions, but for now I just want to get what I have working. I made a method called "checkExceptions", but what would I put inside of it for the program to check that method first before moving on?
import java.util.Scanner;
public class FormingPlurals {
static final String SENTINEL = "done";
static final Scanner IN = new Scanner(System.in);
static String[] exceptions = {"fish", "fox", "deer", "moose", "sheep", "cattle"};
public static void run() {
while (true) {
System.out.println("Enter a word to make it plural. Enter 'done' to stop: ");
String noun = IN.nextLine();
if (noun.toLowerCase().equals(SENTINEL)) {
System.out.println("Goodbye...");
break;
}
System.out.println(makePlural(noun) + " ");
}
}
public static void checkExceptions() {
}
static String makePlural(String singularWord) {
String pluralWord = "";
int length = singularWord.length();
String checker = singularWord.substring(0, singularWord.length() - 1);
char lastLetter = singularWord.charAt(singularWord.length() - 1);
if (length == 1) {
pluralWord = singularWord + "'s";
} else
switch (lastLetter) {
case 's':
case 'x':
case 'z':
pluralWord = singularWord + "es";
break;
case 'h':
if ((singularWord.charAt(singularWord.length() - 2) == 'c') || (singularWord.charAt(singularWord.length() - 2) == 's')) {
pluralWord = singularWord + "es";
break;
}
case 'f':
if (EnglishConsonant(singularWord.charAt(singularWord.length() - 2))) {
pluralWord = checker + "ves";
break;
}
case 'y':
if (EnglishConsonant(singularWord.charAt(singularWord.length() - 2))) {
pluralWord = checker + "ies";
break;
}
default:
pluralWord = singularWord + "s";
break;
}
return pluralWord;
}
public static boolean EnglishConsonant(char ch) {
switch (Character.toLowerCase(ch)) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return false;
default:
return true;
}
}
public static void main(String[] args) {
run();
}
}
It is also possible to do that with arrays, but it is easier to use a map in this case. You could create a map
Map<String,String> irregularPlurals = new HashMap<>();
irregularPlurals.put("sheep","sheep");
irregularPlurals.put("fox","foxes");
Then you could use simply Map interface's methods like get() or containsKey() to check if a given word is has an irregular plural form. A simple method to check it would then be:
String irregularPlural = irregularPlurals.get(singularWord);
if (irregularPlural != null){
return irregularPlural ;
}
BTW, it would be a good idea to rename the methods checkException(), as in Java exceptions and checked exceptions are language concepts, so a reader may think that that method is about handling Java exceptions.
For one, I'd place the exceptions array inside makePlural itself and handle it there.
Secondly, I'd go from the most specialized case to the least one, so
First look at word exceptions
Look at special plurals like 'es', 'ves' etc.
add 's' to the word and return it
Also, the moment I find a match in either the exceptions or special plurals, I'd calculate and immediately return the result, to prevent other rules from matching and adding more stuff to pluralWord
If I had to use a function for the exceptions, it would be
public static boolean isException(String word){
String[] exceptions={"fish", "deer"};
for(int i=0;i<exceptions.length();i++) {
if(exceptions[i].equals(word))
return true;
}
return false;
}
I'm working on a something like music player. I'm building playlist on HashMap, I have a problem with deleting specific setlist(case 5). It works but when I delete position in the middle of the list case 1 (showing all playlists) no longer works because I have empty space (1,2,3,deleted,5,6....). Now how do I make those positions after deleted one decrease index by one? Looks like x-- doesn't solve my problem. I hope you understand my problem, here is the code, if you need me to translate anything to English just ask. Thanks for help!
package PLAYLIST2;
import java.util.HashMap;
import java.util.Scanner;
public class Odtwarzacz {
// String lista;
// Odtwarzacz(Playlist) {
// lista = b;
// }
public static void main(String[] args) {
int nr;
int koniec = 0;
String nazwa11;
int x = 0;
HashMap<Integer, Playlist> Playlista = new HashMap<Integer, Playlist>();
Playlista.put(x, new Playlist("Rock"));
x++;
Playlista.get(0).dodajUtwor("Stockholm Syndrome", "Muse", 2004);
Playlista.get(0).dodajUtwor("Absolution", "Muse", 2004);
Playlista.put(x, new Playlist("Pop"));
x++;
Scanner odczyt = new Scanner(System.in);
// TODO Auto-generated method stub
while (koniec == 0) {
System.out.println("_________________________");
System.out.println("1.Wyświetl listę playlist");
System.out.println("2.Dodaj playlistę");
System.out.println("3.Wyświetl playlistę");
System.out.println("4.Posortuj playlistę");
System.out.println("5.Usuń playlistę");
nr = odczyt.nextInt();
switch (nr) {
case 1: {
System.out.println("Lista playlist: ");
for (int i = 0; i < x; i++) {
System.out.println(i + ". " + Playlista.get(i).Nazwa());
}
break;
}
case 2: {
System.out.print("Podaj nazwę nowej playlisty: ");
nazwa11 = odczyt.next();
Playlista.put(x, new Playlist(nazwa11));
System.out.println("Dodano playlistę: "
+ Playlista.get(x).Nazwa());
x++;
break;
}
case 3: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
Playlista.get(nr).wyswietlListe();
break;
}
case 4: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
Playlista.get(nr).sortuj();
break;
}
case 5: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
System.out.println("Skasowano playlistę: "
+ Playlista.get(nr).Nazwa());
Playlista.remove(nr);
x--;
break;
}
}
}
}
}
You do not seem to need a HashMap.
A HashMap is just a key-value store that has no order.
In your case, a List seems like a better choice. It comes with an order since it is the main point of it.
You can specifically use a ArrayList:
List<Playlist> playlists = new ArrayList<>();
playlists.add(new Playlist("Rock"));
// ...
Playlist p = playlists.get(index);
If you want to safely remove and get correct keys after, you must iterate the Map
int count = 0;
boolean found = false;
Iterator<Map.Entry<Integer,String>> iter = TestMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer,String> entry = iter.next();
if("Sample".equalsIgnoreCase(entry.getValue())){
iter.remove();
found = true;
}
if (found) {
// set the new key using count...
}
count ++;
}
first let me see if i understand your problem correctly or not . you like to reoder playlist after any delete operation. 1,2,3,4,5 . you delete 3 , then it should be 1,2,4,5 and not 1,2, ,4,5.
if above is true , best is use linkedhashmap collection. also case1 you can rewrite as
case 1: {
System.out.println("Lista playlist: ");
for (Playlist pll:Playlista.values()) {
System.out.println(i + ". " + pll.Nazwa());
}
break;
}
I have a text file like with tab delimiter
20001204X00000 Accident 10 9 6 Hyd
20001204X00001 Accident 8 7 vzg 2
20001204X00002 Accident 10 7 sec 1
20001204X00003 Accident 23 9 kkd 23
I want to get the output flight id,total number of passengers, here I have to sum all numerical columns values for total number of passengers Like this
20001204X00000 25
20001204X00001 17
20001204X00002 18
20001204X00003 55
When try to add the four numerical columns I got NullPointer exception, please help how to avoid nullPointerException and how to replace the null or white space values with zero
Actually This is Hadoop Map reduce Java Code
package com.flightsdamage.mr;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class FlightsDamage {
public static class FlightsMaper extends Mapper<LongWritable, Text, Text, LongWritable> {
LongWritable pass2;
#Override
protected void map(LongWritable key, Text value,
org.apache.hadoop.mapreduce.Mapper.Context context)
throws IOException, InterruptedException,NumberFormatException,NullPointerException {
String line = value.toString();
String[] column=line.split("|");
Text word=new Text();
word.set(column[0]);
String str = "n";
try {
long a = Long.parseLong(str);
long a1=Long.parseLong("col1[]");
long a2=Long.parseLong("col2[]");
long a3=Long.parseLong("col3[]");
long a4=Long.parseLong("col4[]");
long sum = a1+a2+a3+a4;
LongWritable pass0 = new LongWritable(a1);
LongWritable pass = new LongWritable(a2);
LongWritable pass1 = new LongWritable(a3);
LongWritable pass3 = new LongWritable(a4);
pass2 = new LongWritable(sum);
} catch (Exception e) {
// TODO: handle exception
}finally{
context.write(word,pass2);
}
}
}
public static void main(String[] args)throws Exception {
Configuration conf = new Configuration();
Job job = new Job(conf, "Flights MR");
job.setJarByClass(FlightsDamage.class);
job.setMapperClass(FlightsMaper.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//FileInputFormat.addInputPath(job, new Path("/home/node1/data-AviationData.txt"));
FileInputFormat.addInputPath(job, new Path("/home/node1/Filghtdamage.txt"));
FileOutputFormat.setOutputPath(job, new Path("/home/node1/output"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
You need to check if the string is of numeric type before parsing it. Like:
int value = 0;
if (StringUtils.isNumeric(str)) {
value = Integer.parseInt(str);
}
If the input string is non numeric (be it null or other non numeric value), StringUtils.isNumeric() will return false and the variable will have 0 as default value.
Here is a simple program which demonstrate the usage of StringUtils.isNumeric()
Test Class:
import org.apache.commons.lang3.StringUtils;
public class LineParse {
public static void main(String[] args) {
String[] input = {
"20001204X00000\tAccident\t10\t9\t6\tHyd",
"20001204X00001\tAccident\t\t8\t7\tvzg\t2",
"20001204X00002\tAccident\t10\t7\t\tsec\t1",
"20001204X00003\tAccident\t23\t\t9\tkkd\t23"
};
StringBuilder output = new StringBuilder();
for (String line : input) {
int sum = 0;
String[] tokens = line.split("\t");
if (tokens.length > 0) {
output.append(tokens[0]);
output.append("\t");
for (int i = 1;i < tokens.length;i++) {
// Check if String is of type numeric.
if (StringUtils.isNumeric(tokens[i])) {
sum += Integer.parseInt(tokens[i]);
}
}
}
output.append(sum);
output.append("\n");
}
System.out.println(output.toString());
}
}
Output:
20001204X00000 25
20001204X00001 17
20001204X00002 18
20001204X00003 55
I have assumed that all the numbers will be Integer. Otherwise use Double.parseDouble().
I have this below program which is not selecting the files within specified period of time please update..whats wrong in it ..
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternFileFilter implements FileFilter {
public static String ITEM_TYPE_FILE = "File"; // for file
public static String ITEM_TYPE_FOLDER = "Folder"; // for folder
public static String ITEM_TYPE_FILE_AND_FOLDER = "FileAndFolder"; // for file and folder
private Pattern fileNamePattern;
public PatternFileFilter(Pattern fileNamePattern) {
this.fileNamePattern = fileNamePattern;
}
public boolean accept(File pathname) {
return fileNamePattern.matcher(pathname.getName()).find() || pathname.isDirectory();
}
public Pattern getPattern() {
return fileNamePattern;
}
public static void searchFile(File topFolderOrFile, String type, PatternFileFilter filter, long timeOut) throws IOException {
long startTimeStamp = Calendar.getInstance().getTimeInMillis();
if (topFolderOrFile.isDirectory()) {
File[] subFoldersAndFileNames = topFolderOrFile.listFiles(filter);
if (subFoldersAndFileNames != null && subFoldersAndFileNames.length > 0) {
for (File subFolderOrFile : subFoldersAndFileNames) {
if (ITEM_TYPE_FILE.equals(type) && subFolderOrFile.isFile()) {
System.out.println("File name matched ----- " + subFolderOrFile.getName());
}
if (ITEM_TYPE_FOLDER.equals(type) && subFolderOrFile.isDirectory()
&& filter.getPattern().matcher(subFolderOrFile.getName()).find()) {
System.out.println("Folder name matched ----- " + subFolderOrFile.getName());
}
if (ITEM_TYPE_FILE_AND_FOLDER.equals(type) && filter.getPattern().matcher(subFolderOrFile.getName()).find()) {
System.out.println("File or Folder name matched ----- " + subFolderOrFile.getName());
}
// You need to decide if you want to process the folders inline // or after you've processed the
// file list...
if (subFolderOrFile.isDirectory()) {
long timeElapsed = startTimeStamp - Calendar.getInstance().getTimeInMillis();
if (((timeOut * 1000) - timeElapsed) < 0) {
System.out.println("Could not complete operation-- timeout");
} else {
searchFile(subFolderOrFile, type, filter, (timeOut * 1000) - timeElapsed);
}
}
}
}
}
}
public static void searchFile(String topFolderName, String type, String fileNamePatternRegExp, long timeOut)
throws IOException {
File topFolderOrFile = new File(topFolderName);
Pattern fileNamePattern = Pattern.compile(fileNamePatternRegExp);
searchFile(topFolderOrFile, type, new PatternFileFilter(fileNamePattern), timeOut);
}
// ***************
public static void main(String[] str) throws Exception {
System.out.println("Type Item to Search ");
System.out.println("1 File");
System.out.println("2 Folder ");
System.out.println("3 Both");
System.out.println("0 Exit");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String searchType = br.readLine();
System.out.println("Enter top folder name ::");
String topFolderName = br.readLine();
System.out.println("Enter name of file to search ::");
String fileName = br.readLine();
System.out.println("Enter timeout period in seconds::");
String timeOutStr = br.readLine();
if (searchType == null || fileName == null || topFolderName == null || timeOutStr == null) {
throw new Exception("Error Occured::Provide both the input Parameters");
}
int searchTypeInd = Integer.parseInt(searchType);
switch (searchTypeInd) {
case 1:
searchFile(topFolderName, ITEM_TYPE_FILE, fileName, Long.parseLong(timeOutStr));
break;
case 2:
searchFile(topFolderName, ITEM_TYPE_FOLDER, fileName, Long.parseLong(timeOutStr));
break;
case 3:
searchFile(topFolderName, ITEM_TYPE_FILE_AND_FOLDER, fileName, Long.parseLong(timeOutStr));
break;
case 0:
System.exit(0);
}
}
}
Please advise if I have folder in D:\saral it should select the files from D: folder
The result I am getting is ...
Type Item to Search 1 File 2 Folder 3 Both 0 Exit 3 Enter top folder
name :: Test Enter name of file to search :: allMfile.txt Enter
timeout period in seconds:: 5
I suggest to invert the logic. Instead of passing in a timeout (and doing complex calculations), calculate the end time outside the method:
long timeOut = System.currentTimeMillis() + Long.parseLong(timeOutStr);
In the method, you can check for a timeout using:
if( System.currentTimeMillis() > timeOut ) { break; }
You also don't end the loop in your code (using break or return) so the check for timeout just prevents the recursive call.
Lastly, consider inverting your if() conditions instead of nesting them:
if (!topFolderOrFile.isDirectory()) { return; }
File[] subFoldersAndFileNames = topFolderOrFile.listFiles(filter);
if (subFoldersAndFileNames == null || subFoldersAndFileNames.length == 0) { return; }
...
I guess that this is wrong:
searchFile(subFolderOrFile, type, filter, (timeOut * 1000) - timeElapsed);
^^^^^^^
Looks like you mix time units: you expect seconds but pass a milliseconds value. In your case, the first timeout you pass is equal to 5 seconds, in the first recursion you pass 5000 seconds and 1000 times more in the next level...
Hint: rename the method parameter to timeOutInSeconds and read your code again.