Building a Scanner with an embedded FileReader recursively in java - java

public static Scanner getFileScanner()
{
try{
Scanner input = new Scanner(System.in);
String file = input.nextLine();
Scanner fs = new Scanner(new FileReader(file));
}catch (FileNotFoundException fe) {
System.out.println("Invalid filename. Try another:");
getFileScanner();
}finally{
return fs;
}
}
I keep getting the error that the variable fs isn't found. I can't figure out why for the life of me.

Your fs is declared under try block... to fix this, declare it outside the block:-
Scanner fs = null;
try {
...
fs = new Scanner(new FileReader(file));
}
catch (FileNotFoundException fe) {
...
}
finally {
return fs;
}

Variables declared inside a try block are not in scope inside the corresponding finally block. There are a number of issues with your approach in general... it's generally not a good idea to return inside a finally block, for example.
Here's what I'd do:
public static Scanner getFileScanner() {
Scanner input = new Scanner(System.in);
File file = null;
while (true) {
file = new File(input.nextLine());
if (file.exists() && file.isFile())
break;
System.out.println("Invalid filename. Try another:");
}
return new Scanner(new FileReader(file));
}

Lets start by listing the problems in your code:
The compilation error on the return statement is caused by fs being out of scope as described in other answers.
When you make the recursive call to getFileScanner(), you don't assign or return the result. So it won't make it back to the caller.
Using a return in a finally block is a bad idea. It will squash (throw away) any other exceptions that might be propagating at that point; e.g. exceptions that don't match a catch or exceptions thrown in a catch block.
The input.nextLine() call will throw an exception if the underlying stream has reached the EOF; e.g. the user typed [CONTROL]+D or whatever. You don't have to catch it (it is unchecked), but the return in the finally block squashes it (probably) resulting in the caller getting a null instead. Ughh ...
Hard-wiring System.in and System.out makes your method less reusable. (OK, this may not be an issue you should address in this particular case. And I won't, below ...)
In theory, your method could be made to throw a StackOverflowError; e.g. if the user hits [ENTER] a number of times. This problem is inherent in your recursive solution, and is a good reason not to do it that way.
Finally, here's a version of the method that addresses these problems:
public static Scanner getFileScanner() throws NoSuchElementException
{
Scanner input = new Scanner(System.in);
while (true) {
String file = input.nextLine();
try {
return new Scanner(new FileReader(file));
} catch (FileNotFoundException fe) {
System.out.println("Invalid filename. Try another:");
}
}
}
Note that I've replaced the recursion, gotten rid of the finally, and declared the exception that is thrown. (One could catch that exception and either report it, or rethrow it as an application specific exception.)

You declared fs in the try block and try to access it in a different scope (the finally block). The usual paradigms is to declare fs before the try block as null.

Declare it first:
public static Scanner getFileScanner() {
Scanner input = new Scanner(System.in);
Scanner fs = null;
while(fs == null) {
try{
String file = input.nextLine();
Scanner fs = new Scanner(new File(file));
}catch (FileNotFoundException fe) {
System.out.println("Invalid filename. Try another:");
}
}
return fs;
}

Just to expand on what the other guys indicated with their code samples...
Because you declare the fs variable within the try block the variable will only be scoped (visible) within the braces immediately after the try keyword.
By moving the fs variable declaration out of the try block and into the getFileScanner method body you are ensuring that the variable can be accessed by all blocks within the method body (try, catch and finally blocks).
Hope that helps!

Related

need help reading a file and displaying contents on a jpanel using setText()

on netbeans, im trying to read a file and display its contents on a swing graphics tab. This is how im reading the file
FileReader reader;
ArrayList<String> file = new ArrayList<String>();
Scanner scan = null;
try
{
reader = new FileReader(filename);
scan = new Scanner(reader);
while(scan.hasNext())
{
file.add(scan.nextLine());
}
return file;
}
catch (IOException e)
{
e.printStackTrace();
}
finally {
scan.close();
}
return null;
This is how I'm writing the file
public String writeFile(ArrayList<String> data)
{
String writer = "";
for (String line : data)
{
writer += (line + lineSeparator);
}
return writer;
}
This is how I'm trying to display it
FileIO file = new FileIO();
String filePath="squeeze.txt";
ArrayList<String> data = file.readFile(filePath);
jTextField1.setText(file.writeFile(data));
And I getting an error on
scan.close();
Your problem here is that scan has not been initialized prior to the try block. Anything in the try block might throw an exception, so therefore you have to write your code assuming that all code in the try block will never be run. Luckily, Java has a syntax just for this situation called try-with-resources. Try-with-resources handles your resources for you, and automatically closes them at the end of the try block. Here is your code, modified to use try-with-resources:
try (FileReader reader = new FileReader(filename);
Scanner scan = new Scanner(reader)) {
while(scan.hasNext()) {
file.add(scan.nextLine());
}
return file;
} catch (IOException e) {
e.printStackTrace();
}
return null;
I also notice that in your catch block, you simply print the stack trace. This is perfectly fine as far as syntax goes, and the compiler will accept it, but I wouldn't recommend swallowing errors like this. If you don't want to do anything special, the best all-purpose line you can use is throw new RuntimeException();. This just throws a generic runtime exception, which will print the stack trace and then terminate the program. This also has the added benefit that you don't need the return null; line at the bottom, since the runtime exception will exit the program anyway, and then any method that calls this method can safely assume that this method returns a non-null value.
jTextField1.setText(file.writeFile(data));
A JTextField is for single lines of text. For multiple lines, use a JTextArea.
As to the problem at hand, the easiest solution is to use methods available to any JTextComponent (which includes both of the above).
Namely JTextComponent.read(Reader,Object) & JTextComponent.write(Writer).

Java I/O File Not Found

Currently trying to write a program to take input from a file and store it in an array. However, whenever I try to run the program the file cannot be found (despite file.exists() and file.canRead() returning true).
Here is my code:
public void getData (String fileName) throws FileNotFoundException
{
File file = new File (fileName);
System.out.println(file.exists());
System.out.println(file.canRead());
System.out.println(file.getPath());
Scanner fileScanner = new Scanner (new FileReader (file));
int entryCount = 0; // Store number of entries in file
// Count number of entries in file
while (fileScanner.nextLine() != null)
{
entryCount++;
}
dirArray = new Entry[entryCount]; //Create array large enough for entries
System.out.println(entryCount);
}
public static void main(String[] args)
{
ArrayDirectory testDirectory = new ArrayDirectory();
try
{
testDirectory.getData("c://example.txt");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
(In it's current state the method is only designed to count the number of lines and create the array)
The console output is as follows: true true c:/example.txt
The program seems to throw a 'FileNotFoundException' on the line where the scanner is instantiated.
One thing I have noticed when checking the 'file' object when debugging is although it's 'path' variable has the value "c:\example.txt", it's 'filePath' value is null. Not sure if this is relevant to the issue or not
EDIT: After Brendan Long's answer I have updated the 'catch' block. The stack trace reads as follows:
java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Unknown Source)
at assignment2.ArrayDirectory.getData(ArrayDirectory.java:138)
at assignment2.ArrayDirectory.main(ArrayDirectory.java:193)
Seemingly the scanner doesn't recognize the file and thus can't find the line
This code probably doesn't do what you want:
try
{
testDirectory.getData("c://example.txt");
}
catch (Exception ex)
{
new FileNotFoundException("File not found");
}
If you catch any exception, you run the constructor for a FileNotFoundException and then throw it away. Try doing this:
try
{
testDirectory.getData("c://example.txt");
}
catch (Exception ex)
{
ex.printStackTrace();
}
According to the javadoc for Scanner, nextLine() throws this exception when there is no more input. Your program seems to expect it to return null, but that's now how it works (unlike, say, BufferedReader which does return null at the end of the input). Use hasNextLine to make sure there's another line before using nextLine.

File is not found yet it is there

I was practicing reading text from a file and could not understand what I was doing wrong. This is what I had at first:
public class Main {
public static void main(String[] args){
File f = new File("C:\\test\\est.txt");
Scanner in = new Scanner(f);
while (in.hasNext()){
System.out.println(in.next());
}
}
}
The compiler said: Unhandled exception java.io.fileNotFoundException.
So I tried this:
File f = new File("C:\\test\\est.txt");
Scanner in = new Scanner(f);
try{
while (in.hasNext()){
System.out.println(in.next());
}
}catch (IOException i){
System.out.println(i.getMessage());
}
Now the compiler said: Unhandled exception java.io.fileNotFoundException. And also: java.io.fileNotFoundException is never thrown in the corresponding try block.
Then I tried this:
File f = new File("C:\\test\\est.txt");
Scanner in = new Scanner(f);
try{
while (in.hasNext()){
System.out.println(in.next());
}
}catch (IOException i){
throw new IOException(i.getMessage());
}
However it still says: Unhandled exception java.io.fileNotFoundException!
Can anyone please explain what I am doing wrong & how I can read all the text from a file in a manner that looks similar to my attempt.
**Note my file DOES exist.
An unhandled exception means that it might be thrown somewhere in your code, but you are not taking it into account when you explicitly have to. So to fix, wrap it in a try-catch:
File f = new File("C:\\test\\est.txt");
try
{
Scanner in = new Scanner(f);
while (in.hasNext()){
System.out.println(in.next());
}
}catch (IOException i){
e.printStackTrace();
}
Note that the Scanner is also inside the try block. Your attempt was good, but the Scanner constructor also might throw a FileNotFoundException. To fix such issues in the future, the compiler tells you exactly which line that throws the exception, not being handled.
Well the error tells you what the problem is ;-)
You are handling the IOException already, but not the FileNotFoundException!
Try like this:
File f = new File("C:\\test\\est.txt");
Scanner in = null;
try {
in = new Scanner(f);
} catch (IOException i){
i.printStackTrace();
}
while (in != null && in.hasNext()){
System.out.println(in.next());
}
edit: Ok actually FileNotFoundException extends IOException, so you don't need to handle it seperately obviously :)
You need to handle the FileNotFoundException by either saying:
throws FileNotFoundException
in your method header. Or adding a catch statement:
}catch (FileNotFoundException ex){
//log it or handle it
}
Also, avoiding throwing the same exception in the catch:
throw new IOException(i.getMessage());
So you want something like:
try{
File f = new File("C:\\test\\est.txt");
Scanner in = new Scanner(f);
while (in.hasNext()){
System.out.println(in.next());
}
}catch (FileNotFoundException ex){
//log it or handle it
}catch (IOException i){
//throw new IOException(i.getMessage());
//log it or handle it
}
Ok, but now the compiler prints java.io.FileNotFoundException:
C:\Users\Cristian\Desktop (Access is denied). Why is "Access denied?"
Make sure you have read access of that directory. Try running your IDE as administrator (you can do this by right-clicking on the IDE and click Run As Administrator).

Help with try/catch and accessing elements within the try

try {
inFile = new Scanner(file);
}
catch (FileNotFoundException e) {
System.out.println("FileNotFoundException");
}
I have this code. However, after the try/catch statement I have the following:
while(inFile.hasNext()) {
}
The compiler is telling me that I have not initialized inFile. Do I need to put all of my code within the try/catch? What am I doing wrong?
Initialize inFile:
Scanner inFile = null;
Edit:
As others have mentioned, you should be careful that you could potentially get a NullPointerException in your while loop. You should consider moving your while loop into the try block as well:
Scanner inFile = null;
...
try {
inFile = new Scanner(file);
while(inFile.hasNext()) {
}
}
catch (FileNotFoundException e) {
System.out.println("FileNotFoundException");
}
The compiler is complaining because if new Scanner() throws FileNotFoundException, inFile won't be initialized (BTW very unfortunate variable name). Your loop should be inside try block, which will also increase readability.
try {
Scanner inFile = new Scanner(file);
while(inFile.hasNext()) {
//...
}
inFile.close();
}
catch (FileNotFoundException e) {
System.out.println("FileNotFoundException");
}
If you are getting a compiler error, you probably need to initialize inFile to null.
Note that later in your code you shouldn't assume that inFile is not null, you should always check it:
e.g.
if (inFile != null) {
while (inFile.hasNext()) {
...
}
}
Yes, you do. If an exception is raised the runtime will print "FileNotFoundException" and will keep running, although inFile will not have been initialized.
You should make the program return when stumbling upon this exception, or else do your operations on infile only when you are sure that it has been initialized correctly.
The try block is not in the same scope as your while loop. Put the while loop inside the try block.
The reason for the warning is that you should set the Scanner to null initially. However you should also move the while loop inside the try block, because if the exception is thrown you don't want that while loop to execute (because inFile will be null).
No your code is fine, however local variables must be intialized so you have to set Scanner inFile = null;
And it is correct what you already have done, because if you move the local variable inside the try/catch statement you will not have access to it because of the scope.
Scanner inFile = null;
try {
inFile = new Scanner(file);
//more code
} catch (Exception e) {
//exception code
}
while (inFile.nextLine()) {
//loop code
}
If you had an instance variable it would have been automatically set to null, but in this case you have a local variable and then objects need to be initialized before you use it.
Yes, as others have said, initialize inFile to null
However, you will also need to check that inFile actually points a valid file and is not NULL when you get to your loop
e.g.
while(inFile!=null && inFile.hasNext()) {
}
Otherwise, you perhaps want to place the whole try-catch in a different loop to make the user select another file? Or just exit the program if the file is invalid? The missing element to the question is how you wish to handle invalid files. Does the program exit or re-prompt the user?

Does everything after my try statement have to be encompassed in that try statement to access variables within it?

I'm learning java and one thing I've found that I don't like, is generally when I have code like this:
import java.util.*;
import java.io.*;
public class GraphProblem
{
public static void main(String[] args)
{
if (args.length < 2)
{
System.out.println("Error: Please specify a graph file!");
return;
}
FileReader in = new FileReader(args[1]);
Scanner input = new Scanner(in);
int size = input.nextInt();
WeightedGraph graph = new WeightedGraph(size);
for(int i = 0; i < size; i++)
{
graph.setLabel(i,Character.toString((char)('A' + i)));
}
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
graph.addEdge(i, j, input.nextInt());
}
}
// .. lots more code
}
}
I have an uncaught exception around my FileReader.
So, I have to wrap it in a try-catch to catch that specific exception. My question is does that try { } have to encompass everything after that in my method that wants to use either my FileReader (in) or my Scanner (input)?
If I don't wrap the whole remainder of the program in that try statement, then anything outside of it can't access the in/input because it may of not been initialized or has been initialized outside of its scope. So I can't isolate the try-catch to just say the portion that intializes the FileReader and close the try statement immediately after that.
So, is it the "best practice" to have the try statement wrapping all portions of the code that are going to access variables initialized in it?
Thanks!
If you are comfortable with not wrapping the code after the FileReader constructor, you can declare the FileReader outside of the try/catch block, like this:
FileReader fr = null;
try
{
fr = new FileReader(args[1]);
}
catch (IOException e)
{
// handle
}
// code that uses fr
This is a reasonable design, and I use it often. Make sure you properly handle, in the following code, the possibility that fr is null (i.e. the constructor threw an exception).
This is not an issue with try/catch blocks as such. The issue is variable scoping and that you must have a try/catch block because of the checked exception and thus establish a new scope.
You also have another option - declare the checked exception(s) as throws from your method.
public static void main(String[] args) throws IOException {
// ...code here...
}
This is perfectly legal for a main method.
If you do want to handle the exception, as you ought to in a larger program. You can define a specific try/catch around the problem block of code and use the variable outside of the scope by declare the variable outside of that scope as many have answered:
FileReader fr = null; // must be initialized here if the exception handling code
// does not exit the method
try {
fr = new FileReader(fileName);
} catch (IOException ex) {
// log, print, and/or return
// if you return or exit here then subsequent code can assume that fr is valid
}
You can also put the move the code to another method that deals with the exception:
private static FileReader openReader(String fileName) {
try {
return new FileReader(fileName);
} catch (IOException ex) {
// log/print exception
return null; // caller must then expect a null
// or
throw new RuntimeException(...); // throw a RuntimeException of some kind (may not be good practice either)
}
}
You could also move the file processing code to another method. This may be better and allow you to more correctly follow the open/close in finally idiom:
FileReader fr = null;
try {
fr = new FileReader(fileName);
Scanner input = new Scanner(fr);
processInput(input);
} catch (IOException ex) {
// log/print exception
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException ex) {
// empty
}
}
}
private static void processInput(Scanner in) throws IOException {
// ...processing here
}
For the close part, you could use a third party library (Apache File Utils) or write a simple method to provide a static safe close method that doesn't throw exceptions.
You really should look at breaking up large methods into smaller units and this will often provide you with a much clearer way of handling the exceptions as well.
No. You can declare it like this:
FileReader in = null;
Scanner input = null;
try {
in = new FileReader(args[1]);
input = new Scanner(in);
} catch(IOException ioe) {
//
}
Yes and no. The Try initiates it's own local scope so when you do this:
try
{
FileReader reader = new FileReader(args[1]);
// Stuff
}
catch(Exception e) { }
The reader variable is only visible within the constraints of the try {} block. This is preferred behaviour. If you want to use it outside (in the case of file i/o it's not reccomended) you need to declare it outside of the try/catch. A proper example would be a flag:
boolean isValidFile = false;
try
{
FileReader reader = new FileReader(args[1]);
// Do Stuff
isValidFile = true;
}
catch(Exception e)
{
// Handle Errors
}
System.out.print("Valid File: ");
System.out.println(isValidFile);
If you are just learning, you can have your method throw Exception. It isn't a great way to handle exceptions however, if you are just learning, you probably want to focus more on the logic of what your code is doing. Once you are comfortable with that, then you can look into handling exceptions properly.
So your code should look like the following and you won't have to worry about try/catch statements:
public class GraphProblem {
public static void main(String[] args) throws Exception {
//your code
}
}
Again, this is not a best practice but it allows you to focus on your business logic rather than error handling. Once you get comfortable with the business logic, then you can dig into exception handling which is a topic onto itself.
Local variables declared within a block are scoped to that block.
So, is it the "best practice" to have the try statement wrapping all portions of the code that are going to access variables initialized in it?
In general, you should try to minimize the scope of your variables to make them as narrow as possible. This is covered in Effective Java and Code Complete, among others.
This sort of code is a recipe for NullPointerExceptions:
FileReader in = null;
try {
in = new FileReader(filename);
} catch(IOException e) {
//handle error, but now what?
}
// Code that needs "in", but what if it is null
// because of a FileNotFoundException?
// This code is junk.
Virtually all local variable declarations should include an assignment.
FileReader in = new FileReader(filename);
If you follow this rule of thumb, you'll end up with better code.
// .. lots more code
If you have giant try/catch statements, it sounds like your methods are too big. This is a code organization issue rather than something to do with try/catch specifically.
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Error: Please specify a graph file!");
return;
}
try {
processGraphFile(args[0]);
} catch (IOException e) {
// Deal with error
}
}
private static void processGraphFile(String filename) throws IOException {
FileReader in = new FileReader(filename);
try {
Scanner scanner = new Scanner(in);
processGraph(scanner);
if (scanner.ioException() != null) {
throw scanner.ioException();
}
} finally {
in.close();
}
}
//other methods
As an aside:
Note that Java arrays start at index 0, not 1
The FileReader is convenient while learning, but should generally be avoided due to encoding issues; this is unlikely to be a problem until the code leaves your machine
You should definitely follow the pattern above. If I remember right from my SCJP studying, the compiler doesn't try to optimize anything that is in a try block, so you should try-catch at the lowest level possible.

Categories

Resources