I have a Scanner that could be reading from either keyboard or from a file (via pipes), and apparently there's no way to tell which.
I have te following code:
Scanner scan = new Scanner(System.in);
while (scan.hasNextLine()) {
String line = scan.nextLine();
doStuff();
}
That works wonderfully when redirecting input to a file. But if I try to run the program by itself and read from keyboard, it enters an infinite loop. Is there a way to differentiate between reading from keyboard and from a file? Thanks in advance!
Edit 1:
As requested by #Abra, this is what my code looks like with your suggestion:
Scanner scan = new Scanner(System.in);
do {
String linea = scan.nextLine();
doStuff();
} while (System.in.available() != 0 && scan.hasNextLine());
And here's the command I'm running:
java -jar Class.jar < File.txt
Edit 2:
Solved it, turns out I should only evaluate System.in.available() != 0 once:
Scanner scan = new Scanner(System.in);
boolean file = System.in.available() != 0;
do {
String linea = scan.nextLine();
doStuff();
} while (file && scan.hasNextLine());
The classic practice used commonly in Linux and Unix is to read input from standard input, as you are already doing. In Java, standard input is called System.in.
The program reads from standard input and processes what it reads in a loop until it detects end-of-file, which you are already doing.
So your program is not stuck - it is merely waiting for more input or for the end-of-file signal to come from the outside.
If you want to use this program with input from a file, you run it like this:
myprogram < input_file.txt
And if you want your program to get its input from terminal (where you type it), you run it just like
myprogram
In this case, and after typing your input, you are also responsible to send a special signal from your terminal that will act as a "end-of-file" and will be picked by the program, causing the while-loop to exit. Typically, you do this by pressing Control-D.
Keep in mind that reading from standard input is not strictly the same as reading from keyboard. Standard input only knows about text and end-of-file; it has no concept of line editing, testing for when shift key is pressed/released etc.
The class of System.in is java.io.InputStream. That class has method available(). If you redirect System.in to a file, as in
myprogram < input_file.txt
Then method available() returns a number greater than zero (assuming that input_file.txt has non-zero size) but when System.in refers to the standard input stream, i.e. when you run your program without redirecting standard input, as in
myprogram
Then method available() returns zero.
based on the answer of #Abra you can break the loop if System.in is keyboard so:
import java.util.Scanner;
import java.io.IOException;
public class Main {
public static void main(String[] argv) throws IOException {
Scanner scan = new Scanner(System.in);
boolean isKeyboard = System.in.available() == 0;
while (scan.hasNextLine()) {
String line = scan.nextLine();
doStuff();
if (isKeyboard) {
break;
}
}
}
}
Related
I'm trying to progress displaying a file line by line with an Enter key, but the if statement that I try doesn't seem to work. If I disregard the if statement, it works, but it feels incomplete because then I'm asking for input and doing nothing with it.
This is what I have:
import java.util.Scanner;
import java.io.*;
public class LineByLine {
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
System.out.println("What is the filename?");
String input = in.nextLine();
BufferedReader buff = new BufferedReader(new FileReader(input));
String sen = buff.readLine();
System.out.println(sen);
Scanner enter = new Scanner(System.in);
while (sen != null){
String output = enter.next();
if (output.equals("")){
System.out.println(sen = buff.readLine());
}
}
}
}
I just don't know why my if statement doesn't work.
The core issue is that you misunderstand Scanner and its default configuration: Out of the box, scanner splits on any amount of whitespace. .next() asks for the next token; a token is the thing that appears in between the whitespace.
Thus, pressing enter 500 times produces zero tokens. After all, tokens are what's in between the separator, and the default separator is 'any amount of whitespace'. Pressing enter a bunch of time is still just you entering the same separator.
The underlying problem is that most people appear to assume that Scanner reads one line at a time. It doesn't do that. At all. But you want it to. So, tell it to! Easy peasy - make scanner do what you already thought it did:
Scanner in = new Scanner(System.in);
in.useDelimiter("\\R"); // a single enter press is now the separator.
You should also stop using nextLine on scanners. nextLine and any other next call do not mix. The easiest way to solve this problem is to only ever use nextLine and nothing else, or, never use nextLine. With the above setup, .next() gets you a token which is an entire line - thus, no need for nextLine, which is good news, as nextLine is broken (it does what the spec says it should, but what it does is counterintuitive. We can debate semantics on whether 'broken' is a fair description of it. Point is, it doesn't do what you think it does).
Also, while you're at it, don't make multiple scanners. And, to improve this code, resources must be properly closed. You're not doing that. Let's use try-with, that's what it is for.
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
in.useDelimiter("\\R");
System.out.println("What is the filename?");
String input = in.next();
try (BufferedReader buff = new BufferedReader(new FileReader(input))) {
String sen = buff.readLine();
System.out.println(sen);
while (sen != null){
enter.next(); // why does it matter _what_ they entered?
// as long as they pressed it, we're good, right? Just ignore what it returns.
System.out.println(sen = buff.readLine());
}
}
}
I need to read data from standard input.
And I want to print it to standard output.
I use Scanner for this:
import java.util.Scanner;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
StringBuilder sb = new StringBuilder();
int countLines = 1;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
sb.append(countLines).append(" ").append(line);
}
System.out.println("finish");
System.out.println(sb.toString());
scanner.close();
}
I input this data:
Hello world
I am a file
Read me until end-of-file.
But hasNextLine()) is always true. And as result never print "finish"
Your code seems to work fine. Are you sure you output EOF correctly? Try Ctrl+D (Cmd+D on Mac) or Ctrl+Z on Windows, as mentioned here: How to send EOF via Windows terminal
There is no condition in which the loop will be false, it'll read the lines forever and ever. Consider adding a stop keyword like "stop"
while(scanner.hasNextLine())
{
String line = scanner.nextLine();
if(line.equalsIgnoreCase("stop"))
{
break;
}
//whatever else you have in the loop
}
Unless you stop it, it'll always be true. As pointed out by #Aaron
Scanner.hasNextLine() blocks waiting for a new line, it will only return false if you close the stream (using Ctrl-Z or D as Liel mentions in his answer)
Say I have the below code
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
line = scanner.nextLine();
//do something
}
And my input in the console is goes like this.
Wayne Rooney
Luis Nani
Shinji Kagawa
I want to read this line by line.
But the problem is the method hasNextLine blocks waiting for the input after the third line as the input from the keyboard (System.in) never reaches EOF.
Now, how do I reach EOF just by pressing enter key? because I don't want to tell the user to press the Ctrl+z to run my program.
How is it generally done? Any thoughts?
I am looking for a solution from the Java side and not any commands on the console.
Thanks in advance
When you press enter twice, you end up reading an empty line. You can test for this:
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (line.equals(""))
break; // this will exit the loop
//do something
}
Now, the loop will end if you press enter twice without typing anything between.
How is it generally done?: It is usually done by showing a message to the user and requesting some special word to finish the input.
public static void main(String[] args) throws IOException
{
Scanner scanner = new Scanner(System.in);
String line;
System.out.println("Enter names (\"QUIT\" to finish)");
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (line.equals("QUIT")) {
break;
}
}
// ...
}
In the example above the special word used is "QUIT", of course you will change this to a more appropriated one.
I have a program that needs to read lines of input. It needs to be many lines at once. For example:
As I enter my time machine or
maybe not,
I wonder whether free will exists?
I wonder whether free will exists
maybe not
as I enter my time machine or.
That all gets entered at one time by the user. I was trying to use .hasNextLine() method from Scanner class, but it is not returning false.... it waits for input again. Ive been looking around for a solution and it appears that .hasNextLine() waits for input, but i do not know what alternative to use. Any suggestions? The actual code looks like:
while(input.hasNextLine());
{
line += input.nextLine();
}
Thanks for your help
Perhaps you should use some sort of "stop" sequence meaning when the user enters a particular character sequence, it will break out the loop. It might look something like:
public static void main(String args[]){
final String stopSequence = "/stop";
final Scanner reader = new Scanner(System.in);
String input = reader.nextLine();
while(!input.equalsIgnoreCase(stopSequence)){
//process input
input = reader.nextLine();
}
}
I'm trying to read commands via a Scanner Object. For checking the Input Syntax I use sc.hasNext() (for the case of missing commands). It did work fine for many cases already, but now I have the case that's described in the JavaAPI as "MAY block and wait for Input".
When does the hasNext() method block and how can I control it? The funny Thing is that it work's perfectly fine with 3 cases before the block. Also the JavaAPI describes hasNext() as the proper method for checking wether there is another Input or not so that the Method next() doesn't produce an Exception.
Here is the code I did produce till now:
if (sc.hasNext() && sc.next().equals("create")) {
if (sc.hasNextInt()) {
width = sc.nextInt();
if (width > 0) {
if (sc.hasNextInt()) {
heigth = sc.nextInt();
if (heigth > 0) {
if (sc.hasNext()) { //At this point the hasNext Statement blocks for //no reason till an Input is made.
charset = sc.next();
Image = new AsciiImage(width, heigth,charset);
} else {
ret = false;
System.out.println("INPUT MISMATCH");
}
} ...//and so on
Thanks in advance, I couldn't find anything on this Topic an my own.
Edit: The Scanner is defined as a System.in, but that shouldn't be a Problem - at least it hasn't been one till now.
There is a difference between testing via Console or via TextFile. If I read from Console the program expects a Stream and it will wait for further Input.
When testing via Input from Textfile (still with System.in for the Scanner, using Java Program ) the hasNext() will return false at the end of the file as no further Input can be done.
I can't really find documentation (in https://docs.oracle.com/javase/9/docs/api/java/util/Scanner.html#hasNext--) on this Topic. So if anyone finds a proper and technical correct answer I would be very greatfull.
If you have nothing else to do while waiting for user input, then it's fine to be blocked at that call until the next input arrives.
If you do want to run other code while waiting for input, spawn a new thread and call hasNext and other blocking scanner methods from there.
I'm not sure , but the following is my own experience :
when the Scanner object is fed with a file , it will not be blocking !
By the term "fed with a file " I mean that the scanner is constructed like this : Scanner scanner = new Scanner("myFile.txt");
But if the scanner is constructed using the getInputStream()method of a Socket object , like this :
input = socket.getInputStream();
Scanner scanner = new Scanner(input);
the scanner will be blocking !