I'm looking to try and create a Java trivia application that reads the trivia from separate question files in a given folder. My idea was to use the run() method in the FileHandler class to set every text file in the folder into a dictionary and give them integer keys so that I could easily randomize the order at which they appear in the game. I found a simple chunk of code that is able to step through the folder and get the paths of every single file, but in the form a Path class. I need the paths (or just the names) in the form a String class. Because I need to later turn them into a file class (which excepts a String Constructor, not a Path). Here is the chunk of code that walks through the folder:
public class FileHandler implements Runnable{
static Map<Integer, Path> TriviaFiles; //idealy Map<Integer, String>
private int keyChoices = 0;
public FileHandler(){
TriviaFiles = new HashMap<Integer, Path>();
}
public void run(){
try {
Files.walk(Paths.get("/home/chris/JavaWorkspace/GameSpace/bin/TriviaQuestions")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
TriviaFiles.put(keyChoices, filePath);
keyChoices++;
System.out.println(filePath);
}
});
} catch (FileNotFoundException e) {
System.out.println("File not found for FileHandler");
} catch (IOException e ){
e.printStackTrace();
}
}
public static synchronized Path getNextValue(){
return TriviaFiles.get(2);
}
}
There is another class named TextHandler() which reads the individual txt files and turns them into questions. Here it is:
public class TextHandler {
private String A1, A2, A3, A4, question, answer;
//line = null;
public void determineQuestion(){
readFile("Question2.txt" /* in file que*/);
WindowComp.setQuestion(question);
WindowComp.setAnswers(A1,A2,A3,A4);
}
public void readFile(String toRead){
try{
File file = new File("/home/chris/JavaWorkspace/GameSpace/bin/TriviaQuestions",toRead);
System.out.println(file.getCanonicalPath());
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
question = br.readLine();
A1 = br.readLine();
A2 = br.readLine();
A3 = br.readLine();
A4 = br.readLine();
answer = br.readLine();
br.close();
}
catch(FileNotFoundException e){
System.out.println("file not found");
}
catch(IOException e){
System.out.println("error reading file");
}
}
}
There is stuff I didn't include in this TextHandler sample which is unimportant.
My idea was to use the determineQuestion() method to readFile(FileHandler.getNextQuestion).
I am just having trouble working around the Path to String discrepancy
Thanks a bunch.
You can simply use Path.toString() which returns full path as a String. But kindly note that if path is null this method can cause NullPointerException. To avoid this exception you can use String#valueOf instead.
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Path path = Paths.get("/my/test/folder/", "text.txt");
String str = path.toString();
// String str = String.valueOf(path); //This is Null Safe
System.out.println(str);
}
}
Output
\my\test\folder\text.txt
Related
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();
}}
I have two files in a directory. Both of them have lines of text in them. According to Notepad++, each line has a CRLF. My ReadFile class reads one file and not the other and not the other.
private FileRead fileRead = new FileRead();
private JobSiteData jobSiteData = new JobSiteData();
private String path = "C:/Users/Antonio/IdeaProjects/JobSearch/websiteTest/";
If I uncomment out the block and comment out the other block it works fine.
#Test
void setAllText_ItReturnsAllLinesFromSite_arrayListOfLinesFromSite() throws IOException {
// ArrayList<String> thisWorks = new ArrayList<>();
// thisWorks = fileRead.getLinesFromFile(path + "allTextTest.txt");
// for (String s : thisWorks) {
// System.out.println(s);
// }
ArrayList<String> thisDoesntWork = new ArrayList<>();
thisDoesntWork = fileRead.getLinesFromFile(path + "goDaddySplitTestAllLines.txt");
for (String s : thisDoesntWork) {
System.out.println(s); // prints "File is empty."
}
}
Here is my FileRead Class.
public class FileRead {
private String fileName;
private ArrayList<String> linesFromFile = new ArrayList<>();
private Scanner fileScanner;
public ArrayList<String> getLinesFromFile(String fileName) {
this.fileName = fileName;
setLinesFromFile();
if (isFileEmpty()) {
linesFromFile.add("File is empty.");
}
return linesFromFile;
}
private void setLinesFromFile() {
File file = new File(fileName);
if (doesFileExist(file)) {
readFile();
closeFileReader();
}
}
private Boolean doesFileExist(File file) {
try {
fileScanner = new Scanner(file);
} catch (FileNotFoundException e) {
linesFromFile.add("File does not exist.");
return false;
}
return true;
}
private void readFile() {
if (fileScanner != null) {
if (!linesFromFile.isEmpty()) {
linesFromFile.clear();
}
while (fileScanner.hasNextLine()) {
linesFromFile.add(fileScanner.nextLine());
}
}
}
private void closeFileReader() {
if (fileScanner != null) {
fileScanner.close();
}
}
private boolean isFileEmpty() {
return linesFromFile.size() == 0;
}
}
UPDATE: I found the issue. For some reason this line in the file is causing the scanner not to read the lines.
"GoDaddy’s Productivity suite of products help millions of small businesses run and grow their ventures. We are looking for an engineer that is passionate about software development to help accelerate our growth. If you’re into building world-class experiences on public cloud infrastructure using JavaScript and React, learning new things, and working with a fun team, we want to meet you!"
This line is the forth line down. If I delete it and everything after it, the scanner works fine. If I delete everything in the file and only have that line in the file as the first line it won't work either. Does anyone know why this is?
I am wondering how to run a same java class with different command line options without manually change those command line options?
Basically, for inputFile and treeFile, I have more than 100 different combinations of the two files. I can not do "edit configurations" in IntelliJ to get result manually for each combination of treeFile and inputFile.
Could anybody give some suggestions to me such that how to create a loop of those inputFile and treeFile so that I do not need to manually specifying them for each combination.
Your help is highly appreciated!!!!
#Option(gloss="File of provided alignment")
public File inputFile;
#Option(gloss="File of the tree topology")
public File treeFile;
My java class code is below:
public class UniformizationSample implements Runnable
{
#Option(gloss="File of provided alignment")
public File inputFile;
#Option(gloss="File of the tree topology")
public File treeFile;
#Option(gloss="ESS Experiment Number")
public int rep = 1;
#Option(gloss="Rate Matrix Method")
public RateMtxNames selectedRateMtx = RateMtxNames.POLARITYSIZEGTR;
#Option(gloss = "True rate matrix generating data")
public File rateMtxFile;
#Option(gloss="Use cache or not")
public boolean cached=true;
private final PrintWriter detailWriter = BriefIO.output(Results.getFileInResultFolder("experiment.details.txt"));
public void run() {
ObjectMapper mapper = new ObjectMapper();
double[][] array;
EndPointSampler.cached=cached;
try (FileInputStream in = new FileInputStream(rateMtxFile)) {
array = mapper.readValue(in, double[][].class);
long startTime = System.currentTimeMillis();
UnrootedTreeLikelihood<MultiCategorySubstitutionModel<ExpFamMixture>> likelihood1 =
UnrootedTreeLikelihood
.fromFastaFile(inputFile, selectedRateMtx)
.withSingleRateMatrix(array)
.withExpFamMixture(ExpFamMixture.rateMtxModel(selectedRateMtx))
.withTree(treeFile);
Random rand = new Random(1);
likelihood1.evolutionaryModel.samplePosteriorPaths(rand, likelihood1.observations, likelihood1.tree);
logToFile("Total time in seconds: " + ((System.currentTimeMillis() - startTime) / 1000.0));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String [] args)
{
Mains.instrumentedRun(args, new UniformizationSample());
}
public void logToFile(String someline) {
this.detailWriter.println(someline);
this.detailWriter.flush();
}
}
There is no way to do this in IntelliJ IDEA. However, you can modify your UniformizationSample class so that it will take the input data as method parameters, and write another Java class that will loop through your inputs and call your class with the necessary parameters.
I wrote getMethod in the file MovieReader and if I print this method inside this file everything is working well.
import java.io.BufferedReader; // scanner
import java.io.FileReader;
public class MovieReader {
private static String text;
public static void main(String args[]) throws Exception {
FileReader file = new FileReader("C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt");
BufferedReader reader = new BufferedReader(file);
text = "";
String line = reader.readLine();
while(line != null) {
text+= line +"\n";
line=reader.readLine();
}
reader.close();
System.out.println(getText()); // This method works
}
public static String getText() {
return text;
}
}
But when I'm trying to call this method from other file it's printing null
public class Userr{
public static void main(String args[]){
MovieReader user = new MovieReader();
System.out.println(user.getText());
}
}
Can you help me with it?
In the MovieReader class you load the file and fill the contents of text in the main() method. When you create a new MovieReader object, the main() method is not executed, so the text field is not initialized.
You can create a static loader method in MovieReader and move the code from main() to there, like this:
public static void loadMovieInfo() {
FileReader file = new FileReader("C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt");
... // rest of the code
reader.close();
}
Just call this before trying to call getText():
MovieReader.loadMovieInfo();
System.out.println(MovieReader.getText());
If you want the file to be loaded and the content of text to be filled when the object is created, you can turn text into an instance variable and load the file info in the MovieReader constructor.
Example:
public class MovieReader {
private String text;
public MovieReader() {
FileReader file = new FileReader("C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt");
BufferedReader reader = new BufferedReader(file);
this.text = "";
String line = reader.readLine();
while(line != null) {
this.text += line +"\n";
line=reader.readLine();
}
reader.close();
}
public String getText() {
return this.text;
}
}
Then this should work:
MovieReader user = new MovieReader();
System.out.println(user.getText());
Also, a couple of observations:
Static methods belong to the class (not to a particular object), and should be called with the name of the class:
MovieReader.getText()
You should use a StringBuilder (docs here) instead of String concatenation to fill the contents of the text variable.
Try this one.
import java.io.BufferedReader; // scanner
import java.io.FileReader;
public class MovieReader {
private static String text;
public static String getText() {
FileReader file = new FileReader("C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt");
BufferedReader reader = new BufferedReader(file);
text = "";
String line = reader.readLine();
while(line != null) {
text+= line +"\n";
line=reader.readLine();
}
reader.close();
System.out.println(getText()); // This method works
return text;
}
}
public class Userr{
public static void main(String args[]){
MovieReader user = new MovieReader();
System.out.println(user.getText());
}
}
The fast and dirty fix: Call the MovieReader.main method.
The longer answer, how you should actually do it:
You probably come from a scripting background like python. What you did here was to create two scripts, basically, wrapped in classes. When you call java, you have one class as entry point, whose main method is called.
So you created one script that loads a file, and another script that reads it, and your expectation is that both main methods are called. You need to go back to design!
The better way would be to only have a minimal main() in MovieReader, and instead have a method like readMovies(), which the main() calls. Then have User.main() call that method as well, before calling getText().
Don't put all the logic in main
First of all, you should call static getText() method with class name.
MovieReader.getText()
Second, default value of static string:
It's initialized to null if you do nothing, as are all reference types.
As, you are not doing anything that's why the value of text is null.
Refer the following fixed code:
MovieReader class
public class MovieReader {
private static String text;
public static void main(String args[]) throws Exception {
FileReader file = new FileReader("C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt");
BufferedReader reader = new BufferedReader(file);
text = "";
String line = reader.readLine();
while(line != null) {
text+= line +"\n";
line=reader.readLine();
}
reader.close();
System.out.println(getText()); // This method works
}
public static String getText() {
return text;
}
}
Userr class:
public class Userr{
public static void main(String args[]){
try {
MovieReader.main(null);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(MovieReader.getText());
}
}
Assuming that you are running the main() method of Userr class.
main() method and getText() method of the class MovieReader are independent of each other. If you are calling getText() method, it will return the value of text variable without any operations on it, cos operations of main() method [ of MovieReader class ] are not going to execute. That's why you are not getting intended result.
try to re factor your code as below.
public class Movie {
public static void main(String[] args) {
MovieReader user = new MovieReader();
String file = "C:/Users/krystian/Desktop/filmDateBaseProject/movies.txt";
System.out.println(user.getText(file));
}
}
and the MovieReader class,
class MovieReader {
private String text;
String getText(String fileName) {
FileReader file;
file = null;
try {
file = new FileReader(fileName);
BufferedReader reader = new BufferedReader(file);
text = "";
String line = reader.readLine();
while (line != null) {
text += line + "\n";
line = reader.readLine();
}
reader.close();
return text;
} catch (FileNotFoundException ex) {
Logger.getLogger(MovieReader.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MovieReader.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
file.close();
} catch (IOException ex) {
Logger.getLogger(MovieReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
}
its always a good practice to use exception handling.
Alright, so I am writing a Java application to import a csv file and then loop through the results, and load them into an array. I am importing the file correctly because it doesn't through an Exception. My issues is that when I try to count the number of records in the FileInputStream I am trapped in an infinite loop. What could be the issue here. Heres the code:
This is my class with a Main method which calls go():
public void go() {
pop = new PopularNames();
popGui = new PopularNamesGui();
String file = popGui.userInput("Enter the correct name of a file:");
pop.setInputStream(file);
pop.getNumberOfNames();
}
This is the class PopularNames (pop), and in the below method I am setting the inputStream var to a new FileINputStream. The file name is provided by the user.
public void setInputStream(String aInputStream) {
try {
inputStream = new Scanner(new FileInputStream(aInputStream));
} catch (FileNotFoundException e) {
System.out.println("The file was not found.");
System.exit(0);
}
}
This is the trouble method. Where I am simply looping through the FileInputStream and counting the number of records:
public void getNumberOfNames() {
while (this.inputStream.hasNext()) {
fileDataRows++;
}
}
public void getNumberOfNames() {
while (this.inputStream.hasNext()) {
inputStream.nextLine(); // Need to read it so that we can go to next line if any
fileDataRows++;
}
}