I am writing a function to take a text file and count how many lines it has while outputting the lines to an array of strings. Doing this I have several exceptions I need to look out for. The class function has several variables that should have a scope throughout the function but when I write a value to the function inside of an exception, the return statement cannot find it. I've moved the declaration around and nothing helps
The value returned "h5Files" "Might not have been initialized" Since I don't know how long the array will be I cannot initialize it to a certain length. I do this within the code and I need a way to tell the return statement that I now have a values
Here is the code
public String[] ReadScanlist(String fileIn){
int i;
String directory ="c:\\data\\"; // "\" is an illegal character
System.out.println(directory);
int linereader = 0;
String h5Files[];
File fileToRead = new File(directory + fileIn);
System.out.println(fileToRead);
try {
FileInputStream fin = new FileInputStream(fileToRead); // open this file
}
catch(FileNotFoundException exc) {
System.out.println("File Not Found");
}
try{
//read bytes until EOF is detected
do {
FileReader fr = new FileReader(fileToRead);// Need to convert to reader
LineNumberReader lineToRead = new LineNumberReader(fr); // Use line number reader class
//
while (lineToRead.readLine() != null){
linereader++;
}
linereader = 0;
lineToRead.setLineNumber(0); //reset line number
h5Files = new String[linereader];
while (lineToRead.readLine() != null){
h5Files[linereader] = lineToRead.readLine(); // deposit string into array
linereader++;
}
return h5Files;
}
while(i !=-1); // When i = -1 the end of the file has been reached
}
catch(IOException exc) {
System.out.println("Error reading file.");
}
try{
FileInputStream fin = new FileInputStream(fileToRead);
fin.close(); // close the file
}
catch(IOException exc) {
System.out.println("Error Closing File");
}
return h5Files;
}
Your code is very very odd. For example these two blocks make no sense:
try {
FileInputStream fin = new FileInputStream(fileToRead); // open this file
}
catch(FileNotFoundException exc) {
System.out.println("File Not Found");
}
try{
FileInputStream fin = new FileInputStream(fileToRead);
fin.close(); // close the file
}
catch(IOException exc) {
System.out.println("Error Closing File");
}
I don't know what you think they do, but besides the first one leaking memory, they do nothing at all. The comments are more worrying, they suggest that you need to do more reading on IO in Java.
Deleting those blocks and tidying the code a (moving declarations, formatting) gives this:
public String[] ReadScanlist(String fileIn) {
String directory = "c:\\data\\";
String h5Files[];
File fileToRead = new File(directory + fileIn);
try {
int i = 0;
do {
FileReader fr = new FileReader(fileToRead);
LineNumberReader lineToRead = new LineNumberReader(fr);
int linereader = 0;
while (lineToRead.readLine() != null) {
linereader++;
}
linereader = 0;
lineToRead.setLineNumber(0);
h5Files = new String[linereader];
while (lineToRead.readLine() != null) {
h5Files[linereader] = lineToRead.readLine();
linereader++;
}
return h5Files;
} while (i != -1);
} catch (IOException exc) {
System.out.println("Error reading file.");
}
return h5Files;
}
My first bone of contention is the File related code. First, File abstracts from the underlying OS, so using / is absolutely fine. Second, there is a reason File has a File, String constructor, this code should read:
File directory = new File("c:/data");
File fileToRead = new File(directory, fileIn);
But it should really be using the new Path API anyway (see below).
So, you declare h5Files[]. You then proceed to read the whole file to count the lines. You then assign h5Files[] to an array of the correct size. Finally you fill the array.
If you have an error anywhere before you assign h5Files[] you have not initialised it and therefore cannot return it. This is what the compiler is telling you.
I don't know what i does in this code, it is assigned to 0 at the top and then never reassigned. This is an infinite loop.
So, you need to rethink your logic. I would recommend throwing an IOException if you cannot read the file. Never return null - this is an anti-pattern and leads to all those thousands of null checks in your code. If you never return null you will never have to check for it.
May I suggest the following alternative code:
If you are on Java 7:
public String[] ReadScanlist(String fileIn) throws IOException {
final Path root = Paths.get("C:/data");
final List<String> lines = Files.readAllLines(root.resolve(fileIn), StandardCharsets.UTF_8);
return lines.toArray(new String[lines.size()]);
}
Or, if you have Java 8:
public String[] ReadScanlist(String fileIn) throws IOException {
final Path root = Paths.get("C:/data");
try (final Stream<String> lines = Files.lines(root.resolve(fileIn), StandardCharsets.UTF_8)) {
return lines.toArray(String[]::new);
}
}
Since I don't know how long the array will be I cannot initialize it
to a certain length.
I don't think an array is the correct solution for you then - not to say it can't be done, but you would be re-inventing the wheel.
I would suggest you use a LinkedList instead, something like:
LinkedList<String> h5Files = new LinkedList<>();
h5Files.add(lineToRead.readLine());
Alternatively you could re-invent the wheel by setting the array to an arbritary value, say 10, and then re-size it whenever it gets full, something like this:
h5Files = new String[10];
if (linereader = h5Files.size())
{
String[] temp = h5Files;
h5Files = new String[2 * linereader];
for (int i = 0; i < linereader; i++)
{
h5Files[i] = temp[i];
}
}
Either one of these solutions would allow you to initialize the array (or array alternative) in a safe constructor, prior to your try block, such that you can access it if any exceptions are thrown
Here is your problem. Please take a look on digested version of your code with my comments.
String h5Files[]; // here you define the variable. It still is not initialized.
try{
..................
do {
h5Files = new String[linereader]; // here you initialize the variable
} while(i !=-1); // When i = -1 the end of the file has been reached
..................
catch(IOException exc) {
// if you are here the variable is still not initialized
System.out.println("Error reading file.");
}
// you continue reading file even if exception was thrown while opening the file
I think that now the problem is clearer. You try to open the file and count lines. If you succeed you create array. If not (i.e. when exception is thrown) you catch the exception but still continue reading the file. But in this case you array is not initialized.
Now how to fix this?
Actually if you failed to read the file first time you cannot continue. This may happen for example if file does not exist. So, you should either return when first exception is thrown or just do not catch it at all. Indeed there is nothing to do with the file if exception was thrown at any phase. Exception is not return code. This is the reason that exceptions exist.
So, just do not catch exceptions at all. Declare your method as throws IOException and remove all try/catch blocks.
Related
I have used the following code to write elements from an arraylist into a file, to be retrieved later on using StringTokenizer. It works perfect for 3 other arraylists but somehow for this particular one, it throws an exception when reading with .nextToken() and further troubleshooting with .countTokens() shows that it only has 1 token in the file. The delimiters for both write and read are the same - "," as per the other arraylists as well.
I'm puzzled why it doesnt work the way it should as with the other arrays when I have not changed the code structure.
=================Writing to file==================
public static void copy_TimeZonestoFile(ArrayList<AL_TimeZone> timezones, Context context){
try {
FileOutputStream fileOutputStream = context.openFileOutput("TimeZones.dat",Context.MODE_PRIVATE);
OutputStreamWriter writerFile = new OutputStreamWriter(fileOutputStream);
int TZsize = timezones.size();
for (int i = 0; i < TZsize; i++) {
writerFile.write(
timezones.get(i).getRegion() + "," +
timezones.get(i).getOffset() + "\n"
);
}
writerFile.flush();
writerFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
==========Reading from file (nested in thread/runnable combo)===========
public void run() {
if (fileTimeZones.exists()){
System.out.println("Timezone file exists. Loading.. File size is : " + fileTimeZones.length());
try{
savedTimeZoneList.clear();
BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("TimeZones.dat")));
String lineFromTZfile = reader.readLine();
while (lineFromTZfile != null ){
StringTokenizer token = new StringTokenizer(lineFromTZfile,",");
AL_TimeZone timeZone = new AL_TimeZone(token.nextToken(),
token.nextToken());
savedTimeZoneList.add(timeZone);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
}
===================Trace======================
I/System.out: Timezone file exists. Loading.. File size is : 12373
W/System.err: java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at com.cryptotrac.trackerService$1R_loadTimeZones.run(trackerService.java:215)
W/System.err: at java.lang.Thread.run(Thread.java:764)
It appears that this line of your code is causing the java.util.NoSuchElementException to be thrown.
AL_TimeZone timeZone = new AL_TimeZone(token.nextToken(), token.nextToken());
That probably means that at least one of the lines in file TimeZones.dat does not contain precisely two strings separated by a single comma.
This can be easily checked by making sure that the line that you read from the file is a valid line before you try to parse it.
Using method split, of class java.lang.String, is preferable to using StringTokenizer. Indeed the javadoc of class StringTokenizer states the following.
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
Try the following.
String lineFromTZfile = reader.readLine();
while (lineFromTZfile != null ){
String[] tokens = lineFromTZfile.split(",");
if (tokens.length == 2) {
// valid line, proceed to handle it
}
else {
// optionally handle an invalid line - maybe write it to the app log
}
lineFromTZfile = reader.readLine(); // Read next line in file.
}
There are probably multiple things wrong, because I'd actually expect you to run into an infinite loop, because you are only reading the first line of the file and then repeatedly parse it.
You should check following things:
Make sure that you are writing the file correctly. What does the written file exactly contain? Are there new lines at the end of each line?
Make sure that the data written (in this case, "region" and "offset") never contain a comma, otherwise parsing will break. I expect that there is a very good chance that "region" contains a comma.
When reading files you always need to assume that the file (format) is broken. For example, assume that readLine will return an empty line or something that contains more or less than one comma.
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).
This is my source:
public static void main(String[] args)
{
File file = null;
Scanner scan = null;
Charset cr = null;
Map<String, Charset> map = null;
try
{
file = new File("D:\\Tests\\New folder (2)\\doncho_encode.txt");
map = cr.availableCharsets();
for (Map.Entry<String, Charset> encoding : map.entrySet())
{
String s = encoding.getKey();
scan = new Scanner(file, s);
// System.out.println(s);
}
System.out.println(scan.nextLine());
}
catch (FileNotFoundException | NullPointerException | IllegalArgumentException e)
{
e.printStackTrace();
}
catch (NoSuchElementException e)
{
System.out.println("Try new encoding");
}
finally
{
if (scan != null)
{
scan.close();
}
}
}
I need to compare different charset value to
scan = new Scanner(file, s);
line and when it find correct to use it. In my example I catch "NoSuchElementException" in catch clause.
I understand, that method availableCharsets() returned to me SortedMap with all encodings, but why wen I compare keys to "scan" the exception is caught? How can look like correct iteration?
In my example text in file is with "UTF-16LE" encoding.
(I am not an expert in using java.util.Scanner, but...)
When looking at the Javadoc for the class I can see that:
the constructor doesn't declare throwing NoSuchElementException
but it's the nextLine method which actually does
So based on that, I guess your problem is not actually that the Scanner doesn't recognize a charset returned by availableCharsets. But actually the
program fails to read the next (first) line from the file.
By the way - what I am saying and suggesting for you to focus is most likely better observable if you add e.printStackTrace(); next to your System.out.println("Try new encoding");.
TLDR: I suspect the expection is thrown for a different reason than you think it is.
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.
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.