This is probably due more to my lack of familiarity with the code than anything else, but I keep having the following problem:
I have a text file that has empty lines, and a scanner that goes through the file.
When I use the .hasNextLine() method, it returns false even though there are more lines in the file. I must point out that the file begins with an empty line, and that the text inside has more empty lines in between, and finally ends with empty lines.
But shouldn't it return true regardless of whether the lines have text or not?
Yes, it should.
Try this:
public static void main(String[] args){
Test t = new Test();
t.testHNL(new File("test.txt"));
}
public void testHNL(File f){
try {
Scanner s = new Scanner(new FileInputStream(f));
while(s.hasNextLine()){
System.out.println("There is another line! :: "+s.nextLine());
}
System.out.println("There are no more lines :'(");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Make sure the file "text.txt" exists, and just carriage returns in it. Then run this.
use the .hasNext() method instead of using the .hasNextLine() method.
You are having problems because the .hasNextLine() method returns true only if the next line has some content in it. Whereas the .hasNext() method returns true even if there is any token in the next line(here the token being \n for the next line)
Taken from the source for SUNs (oracles?) 1.5 JDK, anything which matches the following regular expression is treated as a "line". This includes empty lines under Windows or linux/unix.
private static final String LINE_SEPARATOR_PATTERN =
"\r\n|[\n\r\u2028\u2029\u0085]"
So it should return true even if lines are empty except for carriage return.
Related
I'm trying to read all integers from a file into an ArrayList in the #BeforeClass of a java JUnit test. For testing purposes, I am then simply trying to print all values of the arraylist to the screen. Nothing is being output however. Any input would be greatly appreciated.
public class CalcAverageTest
{
static List<Integer> intList = new ArrayList<Integer>();
#BeforeClass
public static void testPrep() {
try {
Scanner scanner = new Scanner(new File("gradebook.txt"));
while (scanner.hasNextInt()) {
intList.add(scanner.nextInt());
}
for (int i=0;i<intList.size();i++) {
System.out.println(intList.get(i));
}
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
}
}
(promoting a comment to an answer)
If gradebook.txt is an empty file, or starts with something that does not parse as an int, such as text or comments at the top of the file, then scanner.hasNextInt() will immediately return false, and intList will remain empty. The for loop will then loop over the empty list zero times, and no output will be generated, as observed.
I have some strings to skip over before the integers.
scanner.readLine() can be used to skip over comment lines before the numbers. If it is not a set number of lines that need skipping, or if there are words on the line before the numbers, we would need to see a sample of the input to advise the best strategy for finding the numbers in the input file.
You need to iterate over the file till the last line, so you will need to change the condition in the loop and use .hasNextLine() instead of .nextInt()
while (scanner.hasNextLine()) {
String currLine = scanner.nextLine();
if (currLine != null && currLine.trim().length() > 0 && currLine.matches("^[0-9]*$"))
intList.add(Integer.parseInt(currLine));
}
}
Here, we read each line and store it in currLine. Now only if it contains a numeric value it is added to the intList else it is skipped. ^[0-9]$* is a regex used to match only numeric values.
From the docs, hasNextLine()
Returns true if there is another line in the input of this scanner.
This method may block while waiting for input. The scanner does not
advance past any input.
Consider the following java code which opens a file, reads all of the data, then tries to read one more line.
public static void main ( String[] argv) {
FileInputStream inFile = null;
try {
inFile = new FileInputStream("DemoRead.txt");
}
catch ( FileNotFoundException ex) {
System.out.println("Could not open file "+ ex.getMessage());
System.exit(0);
}
Scanner inputStream = new Scanner( inFile);
while ( inputStream.hasNext()) {
System.out.println( inputStream.nextLine());
}
System.out.println(inputStream.nextLine());
inputStream.close();
}
I would expect that the final inputStream.nextLine() would throw an exception as there is nothing else to read.
Indeed if I change the while loop to:
while ( true) {
System.out.println ( inputStream.nextLine());
}
It does throw an exception as expected.
This is not making any sense to me. Any insight would be appreciated.
hasNext() can return false before the end of the file if there are no more tokens left. This is the case when there are only delimiters left at the end of the file.
Compare this with hasNextLine(). If you're using nextLine() then the condition should be hasNextLine(). hasNext() is used with next().
1stly hasNext()--Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.But in case of while loop we always get true.
2ndly in case of nextLine()--Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
so,in case of while(true) we are getting always true and at certain point the nextLine() method finds no line separator so gives exception, but in case of while(hasNext()) method it returns false when there is no token in the file so loop breaks so no Exception comes..
Hope this may help you out.
I have code which consumes an InputStream through a Scanner which looks like
String input = scanner.nextLine().toLowerCase();
if (input.isEmpty()) {
return defaultAnswer;
} else if (input.startsWith("y")) {
return true;
} else if (input.startsWith("n")) {
return false;
}
where the scanner is initialized by a given InputStream coming from IOUtils.toInputStream("someString").
How would I be able to test the if (input.isEmpty()) path?
EDIT:
I swapped two lines in my code, and empty string ("") results in a NoSuchElementException, and a newline or carriage return results in an empty string being returned.
Either using IOUtils.toInputStream("") or new ByteArrayInputStream(new byte[0]) may work.
The latter would certainly provide an empty stream, but it may make your code fail because there isn't an empty line to read - there's no line terminator. For example:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
InputStream stream = new ByteArrayInputStream(new byte[0]);
Scanner scanner = new Scanner(stream, "UTF-8");
String line = scanner.nextLine();
System.out.println(line);
}
}
That fails with:
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Unknown Source)
at Test.main(Test.java:10)
You can use Scanner.hasNextLine() to check whether a call to nextLine() is appropriate or not. You may want to do that in your code. It really depends on whether you're trying to model "input ended without a line" or "the user entered an empty line". Those are significantly different situations, and you should consider both of them.
If you want to provide a stream which contains a line break (i.e. "the user entered an empty line") then you might want to use IOUtils.toInputStream("\n") instead. I'm nervous about the fact that that's not specifying a Charset though - you should carefully consider what encoding you expect your input to be in.
So I have a .txt file with only this as the contents:
pizza 4
bowling 2
sleepover 1
What I'm trying to do is, for example in the first line, ignore the "pizza" part but save the 4 as an integer.
Here is the little bit of code I have so far.
public static void addToNumber() {
PrintWriter writer;
Int pizzaVotes, bowlingVotes, sleepOverVotes;
try {
writer = new PrintWriter(new FileWriter("TotalValue.txt"));
}
catch (IOException error) {
return;
}
// something like if (stringFound)
// ignore it, skip to after the space, then put the number
// into a variable of type int
// for the first line the int could be called pizzaVotes
// pizzaVotes++;
// then replace the number 4 in the txt file with pizzaVote's value
// which is now 5.
// writer.print(pizzaVotes); but this just overwrites the whole file.
// All this will also be done for the other two lines, with bowlingVotes
// and sleepoverVotes.
writer.close();
} // end of method
I am a beginner. As you can see my actual, functioning code is very short and I don't know to proceed. If anyone would be so kind as to point me in the right direction, even if you just give me a link to a site, it would be extremely helpful...
EDIT: I stupidly thought PrintWriter could read a file
It's pretty simple actually. All you need is a Scanner, and it's function nextInt()
// The name of the file which we will read from
String filename = "TotalValue.txt";
// Prepare to read from the file, using a Scanner object
File file = new File(filename);
Scanner in = new Scanner(file);
int value = 0;
while(in.hasNextLine()){
in.next();
value = in.nextInt();
//Do something with the value here, maybe store it into an ArrayList.
}
I have not tested this code, but it should work, but the value in the while loop is going to be the current value of the current line.
I don't fully understand your question, so comment if you want some clearer advice
Here is a common pattern you'll use in Java:
Scanner sc=new Scanner(new File(.....));
while(sc.hasNextLine(){
String[] line=sc.nextLine().split("\\s");//split the string up by writespace
//....parse tokens
}
// now do something
In your case, it seems like you want to do something like:
Scanner sc=new Scanner(new File(.....));
FrequencyCloud<String> votesPerActivity=new FrequencyCloud<String>()
while(sc.hasNextLine(){
String[] line=sc.nextLine().split("\\s");//split the string up by writespace
//if you know the second token is a number, 1st is a category you can do
String activity=line[0];
int votes=Integer.parseInt(line[1]);
while(votes>0){
votesPerActivity.incremendCloud(activity);//no function in the FrequencyCloud for mass insert, yet
votes--;
}
}
///...do whatever you wanted to do,
//votesPerActivity.getCount(activity) gets the # of votes for the activity
/// for(String activity:votesPerActivity.keySet()) may be a useful line too
FrequencyCloud: http://jdmaguire.ca/Code/JDMUtil/FrequencyCloud.java
String num = input.replaceAll("[^0-9]", " ").trim();
For sake of diversity this uses regular expressions.
Sorry if this sounds too simple. I'm very new to Java.
Here is some simple code I was using to examine hasNextLine(). When I run it, I can't make it stop. I thought if you didn't write any input and pressed Enter, you would escape the while loop.
Can someone explain to me how hasNextLine() works in this situation?
import java.util.*;
public class StringRaw {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) {
String str = sc.nextLine();
}
System.out.print("YOU'VE GOT THROUGH");
}
}
When reading from System.in, you are reading from the keyboard, by default, and that is an infinite input stream... it has as many lines as the user cares to type. I think sending the control sequence for EOF might work, such as CTL-Z (or is it CTL-D?).
Looking at my good-ol' ASCII chart... CTL-C is an ETX and CTL-D is an EOT; either of those should work to terminate a text stream. CTL-Z is a SUB which should not work (but it might, since controls are historically interpreted highly subjectively).
CTRL-D is the end of character or byte stream for UNIX/Linux and CTRL-Z is the end of character or byte stream for Windows (a historical artifact from the earliest days of Microsoft DOS).
With the question code as written, an empty line won't exit the loop because hasNextLine() won't evaluate to false. It will have a line terminator in the input byte stream.
System.in is a byte stream from standard input, normally the console. Ending the byte stream will therefore stop the loop. Although nextLine() doesn't block waiting for input, hasNextLine() does. The only way the code terminates, as designed, is with CTRL-Z in Windows or CTRL-D in UNIX/Linux, which ends the byte stream, causes hasNextLine() not to block waiting for input and to return a boolean false which terminates the while loop.
If you want it to terminate with an empty line input you can check for non-empty lines as part of the loop continuation condition. The following code demonstrates how to change the basic question design that uses hasNextLine() and nextLine() to one that terminates if it gets an empty line or an end of input character (i.e. CTRL-Z in Windows or CTRL-D in UNIX/Linux). The additional code in the while condition uses a feature of assignment operators wherein they can be evaluated like an expression to return the value that was assigned. Since it is a String object, the String.equals() method can be used with the evaluation.
Other additional code just adds some printed output to make what is going on obvious.
// HasNextLineEndDemo.java
import java.util.*;
public class HasNextLineEndDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// this code is a bit gee-whiz
// the assignment expression gets assigned sc.nextLine()
// only if there is one because of the &&
// if hasNextLine() is false, everything after the &&
// gets ignored
// in addition, the assignment operator itself, if
// executed, returns, just like a method return,
// whatever was assigned to str which,
// as a String object, can be tested to see if it is empty
// using the String.equals() method
int i = 1; // input line counter
String str = " "; // have to seed this to other than ""
System.out.printf("Input line %d: ", i); // prompt user
while (sc.hasNextLine() && !(str = sc.nextLine()).equals("")) {
System.out.printf("Line %d: ", i);
System.out.println("'" + str + "'");
System.out.printf("Input line %d: ", ++i);
} // end while
System.out.println("\nYOU'VE GOT THROUGH");
} // end main
} // end class HasNextLineEndDemo
Hit Ctrl + D to terminate input from stdin. (Windows: Ctrl + Z) or provide input from a command:
echo -e "abc\ndef" | java Program
I had a similar problem with a socket input stream. Most solutions I found would still block the execution. It turns out there is a not-blocking check you can do with InputStream.available().
So in this case the following should work:
int x = System.in.available();
if (x!=0) {
//Your code
}
As per my understanding , if you take an example of result set object from JDBC or any iterator then in these cases you have a finite set of things and the iterators each time check whether end of the set has been reached.
However in the above case , their is no way of knowing the end of user input i.e. hasNextLine() has no way of knowing when user wants to terminate, and hence it goes on infinitely.
Best way is to put additional condition on the for loop that checks for some condition inside for loop that fails in the future.
In the above post #Jim 's answer illustrates this.
In fact using hasNextLine() as loop terminator for console input should be discouraged because it will never return false.