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.
Related
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.
When I run my code it says that there is an InputMismatchException? Works for the two first read-lines, but hwne I try to read the int and double-lines it doesn't and the string-line doesn't actually read anything into the variable, it is empty as it doesn't print anything at the system.out.println(a +b)... Any tips?
import java.util.*;
import java.io.*;
class Uke55{
public static void main(String[]args){
Scanner input=new Scanner(System.in);
try{
PrintWriter utfil=new PrintWriter(new File("minfil55.txt"));
utfil.println('A');
utfil.println("Canis familiaris betyr hund");
utfil.println(15);
utfil.printf("%.2f", 3.1415);
utfil.close();
}catch(Exception e){
e.printStackTrace();
}
try{
Scanner innfil=new Scanner(new File("minfil55.txt"));
char a=innfil.next().charAt(0);
String b=innfil.nextLine();
System.out.println(a +b);
int c=(int)innfil.nextInt();
double d=(double)innfil.nextDouble();
innfil.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
That's because when you use next(), nextInt(), and nextDouble(), it doesn't go to a new line. Only newLine() moves the cursor to the next line. Do this:
try{
Scanner innfil=new Scanner(new File("minfil55.txt"));
char a=innfil.nextLine().charAt(0); //first error was here. calling next() only
//read A and not the \r\n at the end of the
//line. Therefore, the line after this one was
//only reading a newline character and the
//nextInt() was trying to read the "Canis" line.
String b=innfil.nextLine();
System.out.println(a +b);
int c=(int)innfil.nextInt();
innfil.nextLine(); //call next line here to move to the next line.
double d=(double)innfil.nextDouble();
innfil.close();
}
catch(Exception e){
e.printStackTrace();
}
next(), nextInt(), nextDouble(), nextLong(), etc... all stop right before any whitespace (including the end of a line).
That is because you have in file:
A\n
Canis familiaris betyr hund\n
15\n
3.14
Where \n represents new line character.
When you call first time
innfil.nextLine().charAt(0)
it reads A, and scanner reading points to first \n
Then you call
innfil.nextLine()
it reads till \n (nextLine() reads till \n and puts scanner reading pointer past \n), and makes reading pointer past \n. Reading pointer will be at C in next line.
Then you call
innfil.nextInt()
duh! scanner can't recognize Canis as integer, input mismatch!
According to the documentation on Scanner.nextLine() it
"Advances this scanner past the current line and returns the input that was skipped."
So, after calling char a=innfil.next().charAt(0); the "cursor" is at the end of the first line. Calling String b=innfil.nextLine(); reads until the end of the current line (where there is nothing left to read) and advances to the next line (where the actual String is).
Solution
You need to advance to the next line before calling String b=innfil.nextLine();:
...
char a=innfil.next().charAt(0);
innfil.nextLine();
String b=innfil.nextLine();
...
Note:
Although Scanner.nextInt() and Scanner.nextDouble() behave the same way as Scanner.next(), you don't face the same problem, because those methods will read the next complete token (where "A complete token is preceded and followed by input that matches the delimiter pattern") and white-space characters (such as newline-characters) are considered delimiters. So, those methods will automatically advance to the next line if needed, in order to find the next complete token.
Did you check something is actually written to your file? I doubt that. Try calling flush() before you close your PrintWriter. EDIT: sorry I was wrong here because I was thinking of the auto line flush.
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.
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.
I want to prompt the user to begin entering characters and I want them to be able to enter characters as long as they want until they hit control+d to exit.
For example, they can type a string of numbers like:
1234567
and as soon as they decide to hit control+d the line that they entered will be displayed (so without having to hit return)
I am thinking I'll need a buffered reader or something. Any suggestions?
What rlibby said is spot on: the CTL-D will cause the terminal to flush buffered input to the JVM. However, the keypress event itself is captured and acted on by the terminal and not passed through.
Fortunately, though, it's easy to detect. If the user hits CTL-D on a line of its own, there is no input to flush...which to the JVM is indistinguishable from EOF. Accordingly, System.in.read() will return -1 per the contract of InputStream. If you've wrapped System.in with a BufferedReader, readLine() will return null.
This is my main loop for an interactive command line tool I just wrote:
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
String line;
while((line = systemIn.readLine()) != null) {
// my program loop.
}
One thing worth pointing out is that if the user hits CTL-D after inputting characters (but before hitting return), you'll get those characters. I don't believe there's a way to detect CTL-D when it's not on a line of its own.
DISCLAIMER: I have no idea how this applies to Windows.
http://download.oracle.com/javase/6/docs/api/java/io/BufferedInputStream.html#read%28%29
public class InputTest {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringBuilder out = new StringBuilder();
while (true) {
try {
int c = in.read();
if (c != 4) // ASCII 4 04 EOT (end of transmission) ctrl D, I may be wrong here
out.append (c);
else
break;
} catch (IOException e) {
System.err.println ("Error reading input");
}
}
System.out.println(out.toString());
}
}
You are confusing the roles of your Java program and of the terminal. The terminal buffers input and occasionally supplies it to the Java program, especially after line feeds. Ctrl+D also causes the terminal to make buffered input available, or, if nothing is buffered, to terminate the input. Asking for a program to do something on Ctrl+D is essentially asking it to do something when it reads all available input (and more may become available later). Buffering input on the Java side is going to make things more complicated, rather than less.
Just adding another option for people like me who turn up 9 or so years after the question was asked. If you are using java.util.Scanner, using a String input = in.next(); will drop a NoSuchElementException when Ctrl+d is used. In this case, you can use a try-catch block to catch that particular exception and end execution of your program (either by breaking or changing your iteration value to stop the loop).
import java.util.Scanner;
while (some condition) {
try {
(take your input using the in.next() function here)
...
} catch (java.util.NoSuchElementException e) {
(some condition) = false;
//OR break;
}
}
give this code a try. it actually worked for me
// press ctrl+Z(windows) and ctrl+D(mac, linux) for input termination
StringBuilder out = new StringBuilder();
String text = null;
Scanner scanner = new Scanner( System.in );
while( scanner.hasNextLine() )
{
text = new String( scanner.nextLine() );
out.append( text );
}
scanner.close();
System.out.println( out );
System.out.println( "program terminated" );
In a GUI, you can use a KeyListener.