Basic file scanner exception/issue - java

I'm working on a program for my class that asks for me to read data from a txt file, then display it back. I have created a while loop that reads for hasNext, but I'm running into an exception. It says it's a "no such element exception" and I have no idea why. The loop works for 5 iterations, then gives me the exception
import java.util.Scanner;
import java.text.DecimalFormat;
import java.io.*;
public class Project2_William_Walker
{
public static void main (String[]args) throws IOException
{
File file = new File ("boarding.txt");
Scanner inputFile = new Scanner(file);
DecimalFormat df = new DecimalFormat("0.00");
String title = "Madison Kennel & Grooming";
String fName;
String lName;
String breed;
String weight;
String age;
double highRisk = 20.00;
while (inputFile.hasNext())
{
fName = inputFile.nextLine();
lName = inputFile.nextLine();
breed = inputFile.nextLine();
weight = inputFile.nextLine();
age = inputFile.nextLine();
inputFile.nextLine();
System.out.println(fName + " " + lName + " " + breed + " " + weight + " " + age);
System.out.println();
}
inputFile.close();
System.out.println("End of Program");
}
}
So in my txt file I have a list that has a first name, then a last name, followed by the breed, the weight and then the age. Looks like this:
Will
Walker
Pug
3
4
John
Appleseed
Retriever
15
7
..and so forth for 4 more entries. My loop gets through the first 5 just fine, but then poops out on the 6th and final time through. Thanks for any help!

You are reading 6 lines in the loop, but the loop condition only checks if there is (at least) 1 line to read.
You probably have an extra blank line at the end of the input file, which causes hasNext() to return true after reading in the last block of data.
You would be better to use a for loop the iterates 5 times, each time checking if there's a line available, and each time saving the data into an array.
Something like:
String[] data = new String[5];
while (inputFile.hasNext()) {
Arrays.fill(data, null); // clear out array, in case input is short
for (int i = 0; i < 5 && inputFile.hasNext(); i++)
data[i] = inputFile.nextLine();
if (inputFile.hasNext())
inputFile.nextLine();
System.out.println(data[0] + " " + data[1] + " " + data[2] + " " + data[3] + " " + data[4]);
System.out.println();
}
inputFile.close();

Let's find the source of your problem. To easily do that, let's "map" your nextLine() calls to the file content:
Iteration Code Read line from file
1 fName = inputFile.nextLine(); Will
1 lName = inputFile.nextLine(); Walker
1 breed = inputFile.nextLine(); Pug
1 weight = inputFile.nextLine(); 3
1 age = inputFile.nextLine(); 4
1 inputFile.nextLine(); (empty line between blocks)
2 fName = inputFile.nextLine(); John
2 lName = inputFile.nextLine(); Appleseed
2 breed = inputFile.nextLine(); Retriever
2 weight = inputFile.nextLine(); 15
2 age = inputFile.nextLine(); 7
2 inputFile.nextLine();
As you can see, the last statement inputFile.nextLine() tries to read a line from a file, but there is nothing more to read anymore, because "7" was the last line. So your problem is that you expect that there is always an empty line after a block.
A quick fix would be adding a check, like this:
if (inputFile.hasNextLine())
inputFile.nextLine();
But this can cause trouble if there is no empty line to split two blocks and the next block starts right after the last one.
To avoid such problems in the first place, I would recommond a different file structure. You can for example use a csv with a "," as the delimiter:
Will,Walker,Pug,3,4
John,Appleseed,Retriever,15,7
And read it like this:
final String line = inputFile.nextLine(); // read a single line
final String[] items = line.split(","); // split that line using ','
fName = items[0];
lName = items[1];
breed = items[2];
weight = items[3];
age = items[4];
System.out.println(fName + " " + lName + " " + breed + " " + weight + " " + age);
And to make it even better: create a model class which holds the necessary fields to represent such a line (or a block of your former file style) and let a csv reader like Jackson do the parsing for you.

Related

How to store input line by line from an input file into variables

I am trying to store input of certain data types into variables and print them out into a output file but my code does not seem to work. If I enter the input through std in with System.in Scanner and print to stdout, my code will work. However, when I try what I have, I keep getting this:
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:862)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at Queue.main(Queue.java:17)
Here is my code:
import java.util.*;
import java.io.*;
public class Queue {
public static void main(String[] args) throws IOException {
// open files
// takes input from test-input.txt
Scanner input = new Scanner(new File("test-input.txt"));
// prints output to test-output.txt
PrintWriter output = new PrintWriter(new FileWriter("test-output.txt"));
//Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
int teller = input.nextInt();
String name = input.next();
int simTime = input.nextInt();
int transTime = input.nextInt();
output.println(teller + " " + name + " " + simTime + " " + transTime);
}
// close files
input.close();
output.close();
}
}
My input file contains lines such as:
1 Jesse 2 9
2 Wilson 1 4
3 King 4 8
4 Andy 6 7
You're never consuming the newline character after the transTime
int transTime = input.nextInt();
input.nextLine();
You could also consume the entire line at once, and then split it into types
Try to make sure you are parsing a non empty line, it can happen if your file has extra empty lines, so i suggest do a check inside your while statement
while (input.hasNextLine()) {
final String line = input.nextLine().trim();
if (line.isEmpty()) continue; // continue if line is empty
String [] items = line.split("\\s+");
int teller = Integer.parseInt(items[0]);
String name = items[1];
int simTime = Integer.parseInt(items[3]);
int transTime = Integer.parseInt(items[3]);
output.println(teller + " " + name + " " + simTime + " " + transTime);
}

Reading a text file with more strings on a line and scanner doesn't notice spaces

I'm currently trying to scan through text from a data file and it doesnt recognize the space so it counts it as 2 strings when printed.
while (scanner.hasNextLine())
{
String id = scanner.next();
String species = scanner.next();
String name = scanner.next();
System.out.println(id + "\t" + species + "\t" + name);
lineOfText = scanner.nextLine();
}
That's the code I have and on the line with the space inbetween the species, it prints out the second half of the species and therefore doesn't add the name on the end.

When parsing text file input does not move to next line

I am looking for a little help. I have done quite a bit of googling with little success.
I am new to programming and am sure this is a silly oversight on my part.
The below code is intended to read through a .txt document that is tab delimited. The .txt file is formatted into six columns. Currently, as I move through the file I parse the string to the appropriate value type and assign it to its respective variable. Code is here:
try {
s = new Scanner(new BufferedReader(new FileReader(file))).useDelimiter("\t");
while (s.hasNextLine()) {
group = Integer.parseInt(s.next());
death = Integer.parseInt(s.next());
name = s.next();
sex = s.next();
age = Integer.parseInt(s.next());
fare = Double.parseDouble(s.next());
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
} finally {
if (s != null) {
s.close();
}
}
When I reach the last column of the first row, the variable fare is set to row 1 column 6 AND row 2 column 1. For some reason the line break is not triggering the while loop to restart.
Can anyone help me understand why the while loop does not restart at the end of the line?
File looks like this:
1 5 Bryan male 25 211.3375
1 2 Jimmy male 22 151.5500
There is about 1200 lines of this. When running this loop I get the below error when attempting to set fare = 211.3375 at the end of the first row. For some reason, the line break isn't resetting the loop. I can only assume that the line break is not interpreted as a tab but do not know how to correct this.
Exception in thread "main" java.lang.NumberFormatException: For input string: "211.3375
1"
You're checking Scanner#hasNextLine() but then reading multiple Scanner#next(), a dangerous thing to do. I suggest if you check for next line, you should read next line, and then parse through that line.
e.g.,
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
group = lineScanner.nextInt();
death = lineScanner.nextInt();
name = lineScanner.next();
sex = lineScanner.next();
age = lineScanner.nextInt();
fare = lineScanner.nextDouble();
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
But even this is somewhat dangerous because I'm calling Scanner#next...() without first checking. And so perhaps safer would be to do
String[] tokens = line.split("\\s+");
Then count the tokens length to be sure that it's right, and then parse each individual token that needs parsing to numeric type.
Or you could do something like:
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
if (lineScanner.hasNextInt()) {
group = lineScanner.nextInt();
}
if (lineScanner.hasNextInt()) {
death = lineScanner.nextInt();
}
if (lineScanner.hasNext()) {
name = lineScanner.next();
}
if (lineScanner.hasNext()) {
sex = lineScanner.next();
}
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
}
if (lineScanner.hasNextDouble()) {
fare = lineScanner.nextDouble();
}
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
or use try/catch blocks to check for bad files.

For loop that prints from array

I am trying to print out two separate exam marks for students using a text file.
Below is a screenshot of the text file:
The first column is the student ID and the following two columns are both exam marks
Below is my code that does that calculations and prints:
//for loop that does calculations and prints
for(int i = 0; i < arraySize;i++){
String markOneFull = studentExamOneArray[i];
String markOneString = markOneFull.substring(5,7);
double markOne = Double.parseDouble(markOneString);
examOneNoID[i]= markOne;
String markTwoFull = studentExamTwoArray[i];
String markTwoString = markTwoFull.substring(8,10);
double markTwo = Double.parseDouble(markTwoString);
examTwoNoID[i] = markTwo;
/* String markThreeFull = studentExamThreeArray[i];
String markThreeString = markThreeFull.substring(5,10);
double markThree = Double.parseDouble(markThreeString);
examThreeNoID[i] = markThree;
String markFourFull = studentExamFourArray[i];
String markFourString = markFourFull.substring(5,10);
double markFour = Double.parseDouble(markFourString);
examFourNoID[i] = markFour;
*/
// Aggregate Mark
double aggregate = (examOneNoID[i] + examTwoNoID[i])/2;
DecimalFormat oneDigit = new DecimalFormat("#,##0.0");
//time to write
write.println(studentArray[i] + "\nAB101: " + examOneNoID[i] + " " + " AB102: " + examTwoNoID[i] + " Overall Mark: " + oneDigit.format(aggregate));
write.println("----------------------------------------");
}
write.close();
}
When i run the program i get an error message saying:
Exception in thread "main" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at MarksProcessing.main(MarksProcessing.java:42)
Try something like this:
Scanner sc = new Scanner(new File(fileName));
int i = 0;
while (sc.hasNext())
{
students[i] = sc.nextInt();
studentExamOneArray[i] = sc.nextDouble();
studentExamTwoArray[i] = sc.nextDouble();
double aggregate = (studentExamOneArray[i] + studentExamTwoArray[i])/2;
DecimalFormat oneDigit = new DecimalFormat("#,##0.0");
System.out.println("Student: " + students[i] + " FirstGrade: " + studentExamOneArray[i] + " SecondGrade: " + studentExamTwoArray[i] + " Overal: " + oneDigit.format(aggregate));
i++;
}
Now, you don't need substring and so on. You know the structure of file with grades or whatever that file is. And you don't need extra arrays (you use one for strings and then one for doubles and so on). Just read the numbers into array, then do the math and print.
I think, the specified problem can be easily handled . As we can see that here we are parsing string type into different kind of datatypes , so we should try to catch a Number Format exception.

need help formatting strings in Java

I just started learning Java and I'm having trouble formatting string. In the problem I have a string a user inputted that is a name in the format: "First Middle Last". I need to output the string in the format: "Last, First MI. " (MI is middle initial).
Here is what I have so far, I have the first name working, but unsure how to go about getting the last and middle initial out of the string.
// Variable declarations
String name, first, last, middle;
Scanner scan = new Scanner (System.in);
// Get name from user in format "First Middle Last"
System.out.println("Enter the person's name: ");
name = scan.nextLine();
// Get first, middle initial, and last name from the string
first = name.substring(0, name.indexOf(" "));
middle =
last =
// Output formatted name as "Last, First MI."
System.out.println(last + ", " + first + " " + middle + ".");
so for example if the user entered: "John Robert Doe", it would output as "Doe, John R."
Any help is appreciated.
You can use the split method of the String class
// Get first, middle initial, and last name from the string
String nameParts [] = name.split(" ");
// not sure if you need these variables, but I guess you get the picture
first = nameParts [0];
middle = nameParts [1];
last = nameParts [2];
middleInital = middle.charAt(0);
// Output formatted name as "Last, First MI."
System.out.println(last + ", " + first + " " + middleInital + ".");
Take a look at the String.split method. This allows you to find the substrings. Then you only have to place them in the correct order
Take a look at String split and charAt method of String class.
String person_data = "John Robert Doe" ;
String[] data = person_data.split(" ");
char MI = data[1].charAt(0);
System.out.println(data[2] +","+ data[0] + " "+ MI);
Output = Doe,John R
Here
Data[0] == "John"
Data[1] == "Robert"
Data[2] == "Doe"
MI = first character of Data[1] which is R.
Try this:
String name = "First Middle Last";
String[] data = name.split(" ");
String formatted = String.format("%s, %s %c.", data[2], data[0], data[1].charAt(0));
The last line assigns the value "Last, First M." to the variable formatted, as expected. This solution makes use of Java's Formatter class, which is a big help for all your string formatting needs.
You will need to first split the string (using String.split) and then format it.
Forgive me since I'm typing this on my iPad, the answer will look as follows:
String names = name.split("\\s+"); \\Split on whitespaces, including tab, newline and carriage return.
StringBuilder sb = new StringBuilder();
for (int x = 0; x < names.length; x++) {
switch (x) {
case 0: sb.apppend(names[names.length - 1]).append(", ");
break;
case 1: sb.append(names[0]).append(" ");
break;
case 2: sb.append(Character.toUpperCase(names[1].charAt(0))).append(".");
break;
default: break;
}
}
String fullName = sb.toString();

Categories