I'm writing some code to read an input file of book titles, and putting the read lines into an array and trying to print out the array. But when I try to print out the array, it just returns 'null' for each read line. I'm not sure what I'm doing wrong or what my code is doing. Any suggestions? Thanks!
Code:
import java.io.*;
import java.util.*;
public class LibraryInputandOutputs {
public static void main(String args[]) throws IOException{
int lineCount = 0;
File inputFile = new File("bookTitles.inp.txt");
Scanner reader = new Scanner(inputFile);
while(reader.hasNextLine()) {
reader.nextLine();
lineCount++;
}
String[] bookArray = new String[lineCount];
while (reader.hasNextLine()) {
for (int i = 0; i < lineCount; i++) {
bookArray[i] = reader.next();
}
}
for (int k = 0; k < lineCount; k++) {
System.out.println(bookArray[k]);
}
reader.close();
inputFile.close();
}
}
My text file I'm reading from is 20 book titles, all on different lines.
My output on the terminal is 20 lines of null.
Lets break this down:
This reads every line of the input file, counts each one, and then discards them:
while(reader.hasNextLine()) {
reader.nextLine();
lineCount++;
}
You are now at the end of file.
Allocate a string array that is large enough.
String[] bookArray = new String[lineCount];
Attempt to read more lines. The loop will terminate immediately because reader.hasNextLine() will return false. You are already at the end of file.
So you the statement assigning to bookArray[i] won't be executed.
while (reader.hasNextLine()) {
for (int i = 0; i < lineCount; i++) {
bookArray[i] = reader.next();
}
}
Since bookArray[i] = ... was never executed above, all of the array elements will still be null.
for (int k = 0; k < lineCount; k++) {
System.out.println(bookArray[k]);
}
One solution is to open and read the file twice.
Another solution is to "reset" the file back to the beginning. (A bit complicated.)
Another solution would be to use a List rather than an array so that you don't need to read the file twice.
Another solution is to search the javadocs for a method that will read all lines of a file / stream as an array of strings.
(Some of these may be precluded by the requirements of your exercise. You work it out ... )
The nested loop in step 3 is also wrong. You don't need a for loop inside a while loop. You need a single loop that "iterates" the over the lines and also increments the array index (i). They don't both need to be done by the loop statement itself. You could do one or the other (or both) in the loop body.
Stephen C has already pointed out the main problems with your logic. You're trying to loop twice through the file but you've already reached the end of the file the first time. Don't loop twice. "Merge" both the while loops into one, remove that for loop inside the while loop and collect all the book titles. You can then use the size of the list to print them later on. My Java might be rusty but here it goes -
import java.io.*;
import java.util.*;
public class LibraryInputandOutputs {
public static void main(String args[]) throws IOException {
// int lineCount = 0; - You don't need this.
File inputFile = new File("bookTitles.inp.txt");
Scanner reader = new Scanner(inputFile);
// Use an array list to collect book titles.
List<String> bookArray = new ArrayList<>();
// Loop through the file and add titles to the array list.
while(reader.hasNextLine()) {
bookArray.add(reader.nextLine());
// lineCount++; - not needed
}
// Not needed -
// while (reader.hasNextLine()) {
// for (int i = 0; i < lineCount; i++) {
// bookArray[i] = reader.next();
// }
// }
// Use the size method of the array list class to get the length of the list
// and use it for looping.
for (int k = 0; k < bookArray.size(); k++) {
System.out.println(bookArray[k]);
}
reader.close();
inputFile.close();
}
}
I agree with Stephen C. In particular, using a List is usually better than an array because it's more flexible. If you need an array, you can always use toArray() after the List is filled.
Are your book titles on separate lines? If so you might not need a Scanner class, and could use something like a BufferedReader or LineNumberReader.
Related
This is my piece of code where I am trying to read from a file. My file currently has 4 lines but code is not coming out of the loop after reading those lines.
public void readPhoneBook() throws Exception {
try {
FileReader fileReader = new FileReader(file);
Scanner reader = new Scanner(file);
BufferedReader input = new BufferedReader(fileReader);
while (reader.hasNext()) {
String[] parts = reader.nextLine().split(" ");
if (parts.length == 4){
PhoneBook newPhone = new PhoneBook(parts[0],parts[1],parts[2],parts[3]);
entryList.add(newPhone);
}
fileReader.close();
reader.close();
for (int i=0; i < entryList.size(); ++i) {
entryList.add(new PhoneBook(entryList.get(i).getFirstName(), entryList.get(i).getLastName(),
entryList.get(i).getNumber(),entryList.get(i).getNote()));
System.out.println("2"+entryList.size());
}
}
} catch (Exception NoSuchElementException) {
}
}
The problem is that you are continually augmenting the list, of which the size controls the loop continuation itself:
for (int i=0; i < entryList.size(); ++i) {
...
entryList.add(new PhoneBook(entryList.get(i).getFirstName(),
entryList.get(i).getLastName(),
entryList.get(i).getNumber(), entryList.get(i).getNote()));
The statement entryList.add... is adding a value to the list, such that when the loop's condition is evaluated for the next iteration, entryList.size() will be bigger still.
You can fix it either by reading the size before the loop:
int entryListSize = entryList.size();
for (int i=0; i < entryListSize; ++i) {
Or, even better, by NOT adding values to the same list in the loop. In my opinion, this is the more sensible solution as it doesn't make much sense to add entries to the same list. Maybe you intended to add values to a different list object?
It is not entirely clear for me what the use is of the second loop is. Using Java 8 and streaming you could implement it as follows:
public List<PhoneBook> readPhoneBook(Path file) throws Exception {
return Files.lines(file)
.map(line -> reader.split(" "))
.filter(parts -> parts.length == 4)
.map(parts -> new PhoneBook(parts[0],parts[1],parts[2],parts[3])
.collect(Collectors.toList());
}
}
(the other answer explained the reason why it never stops)
I am trying to write a program where I take a textfile and copy it to another file. In this other file I want one word on the first line, two words on the second, three on the third and so on.
I am having some trouble with the Scanner class however. In the program below I keep getting a NoSuchElementException for line 14. I thought this was because I closed the Scanner in the while loop or something but even when I left out 'in.close()' I kept getting the same error.
Can anybody help me with this?
Thanks in advance.
import java.io.*;
import java.util.*;
public class WordPyramid {
public static void main(String[] args) throws FileNotFoundException {
File inputFile = new File(args[0]);
Scanner in = new Scanner(inputFile);
PrintWriter out = new PrintWriter(args[1]);
int s = 1;
int i = 0;
while (in.hasNext()) {
if (s >= i) {
for (i = 1; i <= s; i++) {
out.print(in.next());
out.print(" ");
}
out.println("");
s++;
}
}
in.close();
out.close();
}
}
A NoSuchElementException is thrown when there is no next() element. While you check to see if the file hasNext() at the start of each layer of the pyramid, you also need to check it before you call next() in the for loop. Your exception is thrown in the for loop because the next layer of the pyramid may require a larger number of words than remains in the file causing next() to try and get an element that is not there.
To fix it, wrap the interior of you for loop with if(in.hasNext()).
hasNext() checks if there is one more token in the scanner's stream. You are checking if there is one more token, and then assuming there are even more than one in your for loop. I would modify your for loop to look like this:
for (i = 1; i <= s && in.hasNext(); i++)
I would like to suggest that your loops are perhaps over-complicated.
Here is what I think is an easier answer, and avoids your exception:
File inputFile = new File(args[0]);
Scanner in = new Scanner(inputFile);
PrintWriter out = new PrintWriter(args[1]);
int s = 1;
int i = 0;
while (in.hasNext()) {
out.print(in.next() + " ");
i++;
if (i == s)
{
// Start the next line
out.println();
s++;
i = 0;
}
}
import java.io.*;
import java.util.*;
import java.text.*;
public class textFile {
public static void main(String args[]) throws IOException {
Scanner sf = new Scanner(new File("C:\\temp_Name\\DataGym.in.txt"));
int maxIndx = -1;
String text[] = new String[1000];
while (sf.hasNext()) {
maxIndx++;
text[maxIndx] = sf.nextLine();
}
sf.close();
double average[] = new double[100];
for (int j = 0; j <= maxIndx; j++) {
Scanner sc = new Scanner(text[j]);
int k = 0;
while (k <= 10) { //attempt to store all the values of text file (DataGym.in.txt) into the array average[] using Scanner
average[k] = sc.nextDouble();
k++;
}
}
}
}
My code doesn't work and keeps giving me this error at the place where I store sc.nextDouble() into the k element of the array:
java.util.NoSuchElementException:
null (in java.util.Scanner)
You should check out the Scanner API. It is suspicious that you have a call to Scanner.hasNext() with a following call to Scanner.nextLine(). There are complimentary calls to check and then get from a Scanner. For instance if you really want the next line then you should check if Scanner.hasNextLine() before calling Scanner.nextLine(). Similarly you call Scanner.nextDouble() without preceding it with a call to Scanner.hasNextDouble().
Also like some of the comments mention you should use a debugger or print statements to see if you are getting what you expect you should be getting. Steps like this are necessary to debugging.
For instance after sf.close you could use System.out.println(Arrays.toString(text)) and judge if the array contains what you expect.
Hope this helps your debugging.
I am trying to take a set of 25 numbers from a text file and convert it into a array. But I am lost.
I have read some other questions similar to this, but all of them used imports and extras, and I don't want to use any imports besides import java.io.*; nor any list.
Also the for loop within this is method is me just messing with it, because I couldn't figure it out.
public static int[] processFile (String filename) throws IOException, FileNotFoundException {
BufferedReader inputReader = new BufferedReader (new InputStreamReader(new FileInputStream(filename)));
String line;
int[] a = new int[25];
while (( line = inputReader.readLine()) != null){
int intValue = Integer.parseInt(line); //converts string into int
for (int i = 0; i < a.length; i++){
a[intValue]++;
}
}
return a;
}
public static void printArray (int[] a) {
for (int i = 0; i<a.length; i++) {
System.out.println (a[i]);
}
}
public static void main(String[] args) throws IOException, FileNotFoundException {
int [] array = processFile("C:\Users\griff_000\Desktop\TestWeek13.txt");
printArray(array);
}
I'm unclear about your whole import restriction, why exactly are you trying to limit the number of imports you have?
Anyway, looking at your code, it seems like the concept of arrays isn't all that clear with you.
Arrays are accessed under the syntax:
array[index] = value;
looking at your code, the line a[intValue]++; is actually finding the array index intValue (the number read from file) and incrementing it by one. Not only is this not what you want, numbers over the array length will cause an ArrayIndexOutOfBoundsException.
Making said amendments we get:
public static int[] processFile (String filename) throws IOException, FileNotFoundException{
BufferedReader inputReader = new BufferedReader (new InputStreamReader(new FileInputStream(filename)));
String line;
int[] a = new int[25];
int i = 0; // We need to maintain our own iterator when using a while loop
while((line = inputReader.readLine()) != null){
int intValue = Integer.parseInt(line); //converts string into int
a[i] = intValue; // Store intValue into the array at index i
i++; // Increment i
}
return a;
}
note the additional variable i being used in this context to facilitate the incrementing index number being used to access the array. If you examine this method carefully, a input file longer than 25 elements would also throw ArrayIndexOutOfBoundsException due to the variable i becoming 25 (beyond the limits of the array). To fix, I'd suggest changing the loop structure to a for-loop (assuming your input array is of fixed size) as follows:
public static int[] processFile (String filename) throws IOException, FileNotFoundException{
BufferedReader inputReader = new BufferedReader (new InputStreamReader(new FileInputStream(filename)));
String line;
int[] a = new int[25];
for(int i = 0; i < a.length; i++){
String line = inputReader.readLine(); // Move the readline code inside the loop
if(line == null){
// We hit EOF before we read 25 numbers, deal appropriately
}else{
a[i] = Integer.parseInt(line);
}
}
return a;
}
Note how the for loop integrates the iterator variable into one nice elegant line, keeping the rest of the code neat and readable.
Your mistake is in the line a[intValue]++;. You are telling Java to find the element at [intValue] and add 1 to it's current value. From your question, I understood that you want to put intValue as the array element.
Since you are using i as the iterator, to add the element simply use:
a[i] = intValue;
What you are doing here:
a[intValue]++;
is increasing the array position of the read value by one. If the number read is 2000 you are increasing a[2000]
you might want to do this
a[i]=intValue;
Hi all I wrote a mergesort program for a string array that reads in .txt files from the user. But what I want to do now is compare both files and print out the words in file one and not in file two for example apple is in file 1 but not file 2. I tried storing it in a string array again and then printing that out at the end but I just cant seem to implement it.
Here is what I have,
FileIO reader = new FileIO();
String words[] = reader.load("C:\\list1.txt");
String list[] = reader.load("C:\\list2.txt");
mergeSort(words);
mergeSort(list);
String x = null ;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length; j++)
{
if(!words[i].equals(list[j]))
{
x = words[i];
}
}
}
System.out.println(x);
Any help or suggestions would be appriciated!
If you want to check the words that are in the first array but do not exist in the second, you can do like this:
boolean notEqual = true;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length && notEqual; j++)
{
if(words[i].equals(list[j])) // If the word of file one exist
{ // file two we set notEqual to false
notEqual = false; // and we terminate the inner cycle
}
}
if(notEqual) // If the notEqual remained true
System.out.println(words[i]); // we print the the element of file one
// that do not exist in the second file
notEqual = true; // set variable to true to be used check
} // the other words of file one.
Basically, you take a word from the first file (string from the array) and check if there is a word in file two that is equal. If you find it, you set the control variable notEqual to false, thus getting out of the inner loop for and not print the word. Otherwise, if there is not any word on file two that match the word from file one, the control variable notEqual will be true. Hence, print the element outside the inner loop for.
You can replace the printing statement, for another one that store the unique word in an extra array, if you wish.
Another solution, although slower that the first one:
List <String> file1Words = Arrays.asList(words);
List <String> file2Words = Arrays.asList(list);
for(String s : file1Words)
if(!file2Words.contains(s))
System.out.println(s);
You convert your arrays to a List using the method Arrays.asList, and use the method contains to verify if the word of the first file is on the second file.
Why not just convert the Arrays to Sets? Then you can simply do
result = wordsSet.removeAll(listSet);
your result will contain all the words that do not exist in list2.txt
Also keep in mind that the set will remove duplicates ;)
you can also just go through the loop and add it when you reached list.length-1.
and if it matches you can break the whole stuff
FileIO reader = new FileIO();
String words[] = reader.load("C:\\list1.txt");
String list[] = reader.load("C:\\list2.txt");
mergeSort(words);
mergeSort(list);
//never ever null
String x = "" ;
for(int i = 0; i<words.length; i++)
{
for(int j = 0; j<list.length; j++)
{
if(words[i].equals(list[j]))
break;
if(j == list.length-1)
x += words[i] + " ";
}
}
System.out.println(x);
Here is a version (though it does not use sorting)
String[] file1 = {"word1", "word2", "word3", "word4"};
String[] file2 = {"word2", "word3"};
List<String> l1 = new ArrayList(Arrays.asList(file1));
List<String> l2 = Arrays.asList(file2);
l1.removeAll(l2);
System.out.println("Not in file2 " + l1);
it prints
Not in file2 [word1, word4]
This looks kind of close. What you're doing is for every string in words, you're comparing it to every word in list, so if you have even one string in list that's not in words, x is getting set.
What I'd suggest is changing if(!words[i].equals(list[j])) to if(words[i].equals(list[j])). So now you know that the string in words appears in list, so you don't need to display it. if you completely cycle through list without seeing the word, then you know you need to explain it. So something like this:
for(int i = 0; i<words.length; i++)
{
boolean wordFoundInList = false;
for(int j = 0; j<list.length; j++)
{
if(words[i].equals(list[j]))
{
wordFoundInList = true;
break;
}
}
if (!wordFoundInList) {
System.out.println(x);
}
}