How do you loop a try/catch statement? I'm making a program that is reading in a file using a Scanner and it's reading it from the keyboard. So what I want is if the file does not exist, the program will say "This file does not exist please try again." then have the user type in a different file name. I have tried a couple different ways to try an do this but, all of my attempts end up with the program crashing.
Here is what I have
try {
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
File file = new File(in.next());
Scanner scan = new Scanner(file);
} catch (Exception e) {
e.printStackTrace();
System.out.println("File does not exist please try again. ");
}
If you want to retry after a failure, you need to put that code inside a loop; e.g. something like this:
boolean done = false;
while (!done) {
try {
...
done = true;
} catch (...) {
}
}
(A do-while is a slightly more elegant solution.)
However, it is BAD PRACTICE to catch Exception in this context. It will catch not only the exceptions that you are expecting to happen (e.g. IOException), but also unexpected ones, like NullPointerException and so on that are symptoms of a bug in your program.
Best practice is to catch the exceptions that you are expecting (and can handle), and allow any others to propagate. In your particular case, catching FileNotFoundException is sufficient. (That is what the Scanner(File) constructor declares.) If you weren't using a Scanner for your input, you might need to catch IOException instead.
I must correct a serious mistake in the top-voted answer.
do {
....
} while (!file.exists());
This is incorrect because testing that the file exists is not sufficient:
the file might exist but the user doesn't have permission to read it,
the file might exist but be a directory,
the file might exist but be unopenable due to hard disc error, or similar
the file might be deleted/unlinked/renamed between the exists() test succeeding and the subsequent attempt to open it.
Note that:
File.exists() ONLY tests that a file system object exists with the specified path, not that it is actually a file, or that the user has read or write access to it.
There is no way to test if an I/O operation is going to fail due to an hard disc errors, network drive errors and so on.
There is no solution to the open vs deleted/unlinked/renamed race condition. While it is rare in normal usage, this kind of bug can be targeted if the file in question is security critical.
The correct approach is to simply attempt to open the file, and catch and handle the IOException if it happens. It is simpler and more robust, and probably faster. And for those who would say that exceptions should not be used for "normal flow control", this isn't normal flow control ...
Instead of using a try catch block, try a do while loop checking if the file exists.
do {
} while ( !file.exists() );
This method is in java.io.File
You can simply wrap it in a loop:
while(...){
try{
} catch(Exception e) {
}
}
However, catching every exception and just assuming that it is due to the file not existing is probably not the best way of going about that.
Try something like this:
boolean success = false;
while (!success)
{
try {
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
File file = new File(in.next());
Scanner scan = new Scanner(file);
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("File does not exist please try again. ");
}
}
Check if the file exists using the API.
String filename = "";
while(!(new File(filename)).exists())
{
if(!filename.equals("")) System.out.println("This file does not exist.");
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
filename = new String(in.next();
}
File file = new File(filename);
Scanner scan = new Scanner(file);
Related
I'm new to coding, and very new to java, so please bear with me, I'm sorry.
My professor says we need to use the following code as part of our assignment. I've looked through all my notes for the class, and I cannot find anything on try-catch and I'm not sure what I'm supposed to put in the insert code part or what the error message means
I'm very sorry, I'm just very confused. I keep getting
"Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body"
and I don't know how to fix it
try
{
File file = new File( args [ 0 ] );
Scanner scanner = new Scanner( file );
//insert code
scanner.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Edit: I didn't get that error again after fixing it until I tried hard-coding a text file to test things out.
try
{
File file = new File( args [ 0 ] );
Scanner scanner = new Scanner("cat.txt");
//insert code
scanner.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
I am once again getting "Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body"
What am I supposed to put in the try statement? I am so lost
I didn't get that error again after fixing it until I tried hard-coding a text file to test things out.
try
{
File file = new File( args [ 0 ] );
Scanner scanner = new Scanner("cat.txt");
//insert code
scanner.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
I am once again getting "Unreachable catch block for FileNotFoundException.
new Scanner(String) is not the same as new Scanner(File). If you look at the documentation, the first (using a String) reads from the string, not from a file. Since no file is involved, there's no FileNotFoundException.
If you want to hardcode the filename for testing purposes, do that in the new File(...) line, not the new Scanner(...) line:
try
{
File file = new File("cat.txt"); // <==== Here
Scanner scanner = new Scanner(file);
//insert code
scanner.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
That will compile, because new Scanner(File) throws FileNotFoundException.
Welcome to SO! Exceptions are a great way to catch errors and decide how to handle them. Some segments of code require the program to take a leap and attempt to perform a task that may not be possible at that moment.
The errors specified in the question are a result of the Scanner not finding the file at the specified file path. The ArrayIndexOutOfBounds is indicating exactly what the exception states. The index being accessed is outside the bounds(size) of the array.
Java docs is a great resource and this should help clarify the purpose of catch statements.
https://docs.oracle.com/javase/tutorial/essential/exceptions/catch.html
I've encountered an issue in Java trying to write to a file using FileWriter. Simply declaring FileWriter writer = new FileWriter("filelocation"); yields that there is an unreported IOException which must be caught.
To rectify this, naturally I put my FileWriter within a try-catch block, but that causes an issue with scope. To fix this, I tried declaring the FileWriter before the try catch block and assigning the location within the try catch. After the try catch block when I would like to use the FileWriter, it tells me it may not have been initialized. I'm not certain how else to handle this, and never encountered this issue in Java 1.7 or likewise.
This is an example of my final situation in case I was unclear;
Scanner userInput = new Scanner(System.in);
FileWriter writer;
try {
System.out.println("Enter the file directory you would like to store in");
String fileLocation = userInput.nextLine();
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Error message");
}
writer.write("Stuff"); //writer may not have been initialized
The good way :
System.console().printf("Enter the file directory you would like to store in");
String location = System.console().readLine();
try (FileWriter writer = new FileWriter (location)) {
writer.write("Stuff");
} catch (IOException e) {
new RuntimeException("Error message", e).printStackTrace();
}
Explanations:
System.console().printf() enable to print message on stdout. System.out may be prefered is having a "console" is not strictly required.
Uses System.console() for console management. Much easier and clearer. Don't forget to allocate a console (ie don't use javaw executable).
Opens stream using try-with-resources statement
printStackTrace() print on stderr the call stack which ease finding error location in code.
I have built a new Exception to attach your error message with the stack trace adds the "catch" location in the stack.
Advices:
Uses byte-stream for file access (ie FileOutputStream). It enables to enforce charset (ie OutputStreamWriter) and buffering (ie BufferedOutputStream or BufferedWriter).
Using byte-stream makes also possible to switch to NIO Channel API.
Uses StandardCharsets to access default (and largely commonly used) charset (Charsets that all JVM implementations must support)
Read The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
call to printStackTrace() isn't really nice and you should quickly introduce a logging system to print messages.
In case of a CLI, have good attention when using logging system to not confuse user about system interactions (ie prompt for user input) and feedbacks (ie progress message)
You say "naturally" you put it within a try-catch block. There's nothing natural about that, since there are two ways to handle it, and the other way is more common:
Handle the exception in a try-catch block.
Don't handle the exception, but declare that your method throws the exception, and allow it to cascade up the call stack.
Your code looks like it's in a main method, so you could add throws IOException:
public static void main(String[] args) throws IOException {
In your particular case, however, you're getting the file location from a user prompt, so rather than letting the program die with an error, the appropriate thing would be to tell the user about the error and prompt for a new name.
Also, remember to close your resources.
public static void main(String[] args) throws IOException {
Scanner userInput = new Scanner(System.in);
FileWriter writer;
do {
System.out.println("Enter the file name you would like to store in");
String fileLocation = userInput.nextLine();
if (fileLocation.trim().isEmpty())
return; // Exit program when user pressed enter with a name
try {
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Cannot write to file: " + e);
writer = null;
}
} while (writer == null);
try {
writer.write("Stuff"); //writer may not have been initialized
} finally {
writer.close();
}
}
The write and the close can still technically throw an error (e.g. disk full), which we allow to cascade and kill the program.
I'm having problems with my try-catch exception here. Actually what it does is to prompt the user for the name of a text file say, Robot.txt but if say the file does not exist, I have to make sure that the application reprompts the user for the file name. Hope you guys can understand I'm still a newbie here so please feel free to provide suggestions or advices on my coding etc. Cheers!
Main method class:
import java.io.*;
import java.util.Scanner;
import java.util.Vector;
class TestVector3 {
public static void main(String [] args)
{
System.out.println("Please enter the name of the text file to read: ");
Scanner userInput = new Scanner(System.in);
Vector <KillerRobot> robotDetails = new Vector <KillerRobot>();
KillerRobot robot;
Scanner fileInput = null;
try
{
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
System.out.println("Re-enter file name :"); //Reprompt user for name of the text file
fileInput = new Scanner(userInput.nextLine());
}
while(fileInput.hasNext())
{
robot = new KillerRobot();
String first = fileInput.next();
robot.setName(first);
String second = fileInput.next();
robot.setMainWeapon(second);
int third = fileInput.nextInt();
robot.setNumberOfKills(third);
robotDetails.add(robot);
}
for(KillerRobot i : robotDetails)
{
System.out.println(i);
}
fileInput.close();
}
}
KillerRobot class file:
class KillerRobot {
private String name;
private String mainWeapon;
private int numberOfKills;
KillerRobot()
{
}
public String getName()
{
return name;
}
public String getMainWeapon()
{
return mainWeapon;
}
public int getNumberOfKills()
{
return numberOfKills;
}
public String toString()
{
return name + " used a " + mainWeapon + " to destroy " + numberOfKills + " enemies ";
}
public void setName(String a)
{
name = a;
}
public void setMainWeapon(String b)
{
mainWeapon = b;
}
public void setNumberOfKills(int c)
{
numberOfKills = c;
}
}
As you state that you are a beginner, let us first look at the relevant part of your code, to make sure that we talk about the same thing:
Scanner fileInput = null;
try {
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e) {
System.out.println("Error - file not found!");
System.out.println("Re-enter file name :");
fileInput = new Scanner(userInput.nextLine());
}
You have an input and you want to check this input for a condition and require a new input until this condition is fulfilled. This problem can be solved using a loop like the following:
Scanner fileInput = null;
do {
System.out.println("Enter file name :");
try {
fileInput = new Scanner(new File(userInput.nextLine()));
} catch (FileNotFoundException e) {
System.out.println("Error - file not found!");
}
} while(fileInput == null);
So finally, why does this work? The fileInput variable is set to null and will remain null until the given file is successfully read from standard input because an exception is thrown otherwise what prevents the fileInput variable to be set. This procedure can be repeated endlessly.
On a side note, for performance reasons, it is normally not a good idea to implement control flow that is based on exceptions. It would be better to check for a condition if a file exists via File::exists. However, if you read the file after checking for its existence, it might have been deleted in the meantime which introduces a racing condition.
Answer to your comment: In Java (or almost any programming language), you can inline expressions. This means that instead of calling two methods in two different statements as in
Foo foo = method1();
Bar bar = method2(foo);
you can simply call
Bar bar = method2(method1());
This way, you save yourself some space (what becomes more and more important if your code gets longer) as you do not need the value that you saved in foo at any other place in your code. Similarly, you can inline (which is how this pattern is called) from
File file = new File(userInput.nextLine())
fileInput = new Scanner(file);
into
fileInput = new Scanner(new File(userInput.nextLine()));
as the file variable is only read when creating the Scanner.
Try putting the try-catch in a loop like below:
Scanner fileInput = null;
while (fileInput==null)
{
try
{
System.out.println("Please enter the file name.");
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
}
}
Next you could think of moving the File creation part into separate method, so that the code was cleaner.
Do not fall for try-catch instead add this as your functionality. Exceptions are naturally for run time error handling not for logic building.
Check if file exists at given location.
File textFile = new File(userInput.nextLine());
// Check if file is present and is not a directory
if(!textFile.exists() || textFile.isDirectory()) {
System.out.println("Error - file not found!");
//Reprompt user for name of the text file
System.out.println("Re-enter file name :");
fileInput = new Scanner(userInput.nextLine());
}
You can put while loop instead of if loop if you want to continuously prompt user until correct path is entered.
You can call back your main(), like following
try
{
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
main(args); // recursively call main() method
}
Now if user first attempt wrong then your code will asked to re enter file name.
How to check isFile exist?
File file = new File(filePathString);
if(file.exists() && !file.isDirectory()){
System.out.println("file exist");
}
This really is an XY problem because you assumed the only way to check for a file existence is by catching a FileNotFoundException (hence asking about try-catch exception handling) whereas other means exist to help you avoid a try-catch idiom in an elegant manner.
To check if a file exists at the given path or not you can simply use the File.exists method. Please also see the File.isFile method and/or the File.isDirectory method to verify the nature of the targeted File object.
EDIT : As stated by raphw, this solution is best used in simple scenario since it can incur a race condition in the case of concurrent file deletion happening during the file existence check. See his answer for handling more complex scenario.
I have a java class where a user provides a file path and if the path doesn't exist I ask them to try again. My professor says we should use an exception to handle this.
Here is a snippet of how I'm currently doing it:
public class SalesUtil {
public static void processSales() {
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter sales file name: ");
String salesFile = keyboard.nextLine();
try {
Scanner scanFile = new Scanner(new File(salesFile));
//do stuff
}
} catch(FileNotFoundException fnfe) {
System.out.println("Invalid file name supplied, please try again.");
processSales();
}
}
}
Well in the do stuff section, I'm calculating values and printing data to the console. If I enter the correct file name correctly on the first try all the data is correct. If it is incorrect one or more times the data is not correct.
I imagine this is because of adding function calls on top of my initial stack and never 'getting out' of the initial stack while supplying subsequent stack calls until the correct file is supplied?
I'm still new to java and would appreciate some tips in understanding how to solve this using an exception.
The FileNotFoundException is the correct one to catch, however I gather that you're worried about the stacks building up? I tested reading back the file after multiple failed attempts and it was fine. The recursive call is at the end of the method so it is the last line of code and therefore the stacks shouldn't have any effect.
However, if you want, you could use a while loop instead of recursion to avoid stack buildup:
public static void processSales() {
Scanner scanFile = null;
Scanner keyboard = new Scanner(System.in);
while (scanFile == null) {
System.out.println("Enter sales file name: ");
String salesFile = keyboard.nextLine();
try {
scanFile = new Scanner(new File(salesFile));
while (scanFile.hasNextLine()) {
System.out.println(scanFile.nextLine());
}
} catch(FileNotFoundException fnfe) {
System.out.println("Invalid file name supplied, please try again.");
}
}
}
use the file.exist() method to check, if that what you want to do is to make sure it exist then this is the codes:
File sfile = new File(salesFile);
if (sfile.exists()) {
// ok, file exist do something.
...
}
On the other hand, when you say "invalid file" could be anything, if it is bad filename, then it is another animal (well, different exeception)...
To use try/catch for a readonly file then:
try {
FileInputStream sfile = new FileInputStream(salesFile);
...
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
}
I have a method called readinFile and if the user enters a wrong file instead of exiting I wanted to call the method readinFile again inside the readinFile method I ask the user for new filename. The problem I am running into is the first time it goes through it and gives the exception file not found than it goes through the catch(). I want it to call the method and not run the last inputStream.
try
{
inputStream = new Scanner(new FileInputStream(fileName));
}
catch(FileNotFoundException E)
{
readinfile(table, numberOfColumns, header,
original, sntypes,displaySize,
writeOut,inputStream,fileName );
System.out.print("It got here after doing the method call");
}
You should generally not use exceptions for branching. Just check for the existance of the file using File.exists, like so:
new File(fileName).exists()
You probably want to do something like this:
String fileName;
do {
System.out.println("Please enter filename");
fileName = getFileNameFromInput();
File file = new File(fileName);
} while (!file.exists());
readFile(file);
EDIT:
As Bruno Reis has pointed out, this will only check if the file exists when the user specified the file name. If the file was to be moved/deleted between specifying the file name and reading it then a FileNotFoundException would still be thrown.
To reduce the risk of this you can lock the file as discussed in this question.
bool invalidFilename = true;
string fileName;
while(invalidFilename)
{
readinfile(...);
invalidFilename = !new File(fileName).exists();
}
inputStream = new Scanner(new FileInputStream(fileName));
You can check if the filename the user input does exists or not, and don't need to catch the exception. (which is not a good design code, decrease the readability of the code)....
as inflagranti said,
you can do this pseudocode
if (!new File(filename).exists()){
//read your other file from user
readinfile(....)
}
To get what you are after, without the chance of the file being deleted after you check for it existing but before you open it do something like:
boolean done = false;
String fileName = fileNameParameter;
while(!done)
{
try
{
inputStream = new Scanner(new FileInputStream(fileName));
done = true;
}
catch(FileNotFoundException E)
{
fileName = /* ask the user for the file name */
}
}