Flush/Clear System.in (stdin) before reading - java

At work, we have 5 RFID readers attached to a PC running Linux. The readers are all recognized as keyboards and send their input (what they read form the Chip) as an key-input-event sequence. To be able to tell which reader send what sequence, I'm doing a raw-read over /dev/input/XX and get their input this way.
The problem with this is, that the send keyboard-events generated by the RFID readers are still "in" stdin and when I try to read from System.in via Scanner (input should be generated by a normal keyboard this time), I first get the "pending" input from the readers (which consists of 10 Hex-decimal digits and a newline (\n)).
Now, the question is: How can I flush all these "pending" input's from stdin and then read what I really want from the keyboard?
I tried:
System.in.skip(System.in.available());
But seek is not allowed on stdin (skip throws an IOException).
for (int i = 0; i < System.in.available(); i++){
System.in.read();
}
But available() doesn't estimate enough (still stuff in stdin afterwards).
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
scanner.nextLine();
}
System.out.println("Clean!");
But hasNextLine() never becomes false (the print never executes).
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null);
System.out.println("Clean!");
Same as above.
Anyone with any more ideas?

Based on #Joni's advice, i put this together:
Scanner scanner = new Scanner(System.in);
int choice = 0;
while (scanner.hasNext()){
if (scanner.hasNextInt()){
choice = scanner.nextInt();
break;
} else {
scanner.next(); // Just discard this, not interested...
}
}
This discards the data that is already "pending" in stdin and waits until valid data is entered. Valid, in this context, meaning a decimal integer.

This worked for me
System.in.read(new byte[System.in.available()])

A related one.
I read a double, then needed to read a string.
Below worked correctly:
double d = scanner.nextDouble();
scanner.nextLine(); // consumes \n after the above number(int,double,etc.)
String s = scanner.nextLine();

There is no built-in portable way to flush the data in an input stream. If you know that the pending data ends with \n why don't you read until you find it?

Devices usually send data using a well defined protocol which you can use to parse data segments.
If I'm right, discard data that isn't properly formatted for the protocol. This allows you to filter out the data you aren't interested in.
As I'm not familiar with the RFID scanner you're using I can't be of more help, but this is what I suggest.

You could do this with multiple threads.
Your real application reads from a PipedInputStream that is connected to a PipedOutputStream
You need to have one thread reading from System.in continuously. As long as the real application is not interested in the data coming from System.in (indicated by a boolean flag), this thread discards everything that it reads. But when the real application sets the flag to indicate that it is interested in the data coming from System.in, then this thread sends all the data that it reads to the PipedOutputStream.
Your real application turns on the flag to indicate that it is interested in the data, and clears the flag when it is no longer interested in the data.
This way, the data from System.in is always automatically flushed/clead

The best practice (that I've found) when dealing with terminals (aka. the console) is to deal with i/o a line at a time. So the ideal thing to do is get the entire line of user input, as a string, and then parse it as you see fit. Anything else is not only implementation specific, but also prone to blocking.
Scanner sc = new Scanner(System.in);
String line = "";
while (true) {
System.out.println("Enter something...");
try {
line = sc.nextLine();
//Parse `line` string as you see fit here...
break;
} catch (Exception e) {}
}
I include the while & try/catch blocks so that the prompt will loop infinitely on invalid input.

You can try:
System.in.skipNBytes(System.in.available());

Related

Reading System.in character by character without buffering

I know that similar questions have been asked before, but not exactly what I'm asking. To begin with, let me explain my purpose. I'm trying to write a kind of "remote shell" that will take in characters from the console (System.in) on character at a time and then send those to a remote session on another machine, write them to that machine and gather any characters it might output to return to my shell to display back to the user.
So, the issue is that System.in, no matter what I do, doesn't really support a "raw" mode where any type of reader is able to read just one character at a time UNTIL a terminator character is entered, typically new line.
Things I have tried, Using Scanner, using a buffered reader, creating a FileDescriptor.in and creating a fileInputStream from that, using a FileChannel and reading into a ByteBuffer that is one character long, etc. In all cases, it seems, System.in only makes characters available to the java application after a terminator character has been entered by the user. I'm convinced there is not a "java" way to do this, so the question is, does anyone have some native code, wrapped in a java library to do this? Its hard to find such a thing just searching GitHub.
BTW, for the remote console, I'm using the pty4J package. I've seen sample projects that connect to that code using other langauages, for example javaScript running in a browser to create a web based shell. Other languages all you to do a simple "get_char" on standard in.
Some examples of the code I've tried:
Scanner scanner = new Scanner(System.in);
FileDescriptor fd = FileDescriptor.in;
FileInputStream fis = new FileInputStream(fd);
FileChannel fc = fis.getChannel();
while(process.isAlive()) {
System.out.println(scanner.next());
// ByteBuffer bb = ByteBuffer.allocate(1);
// int c = fc.read(bb);
// int c = fis.read();
// System.err.println("Read " + c);
// if (c == 1) {
// os.write(bb.get());
// }
}
You can see that I've tried various methods to read the input: scanner.next(), fc.read(byteBuffer), fileInputStream.read(), etc. All attempts "wait" till a terminator character is entered.
Additionally, I have tried using the "useDelimiter" and "next(pattern)" methods on the scanner too. That's still not working.
Any pointer or help is much appreciated.
Below is an example of reading one character at a time until end of stream is reached. On linux, you type control-d to signal the end input. I think on Windows, you type control-c to end of input.
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
int c = 0;
while( (c=System.in.read()) != -1){
System.out.println((char) c);
}
}
}

Is BufferedReader blocking the standard console input?

I'm writing a simple chat application in Java and everything works fine except the following strange bug:
When you type something in the terminal, for example you press "a" and the console writes "a", then you press "i", it writes "i", "r" -> "r"... and you get the word (e.g. "air") written in console.
In my case I press "e", the console writes "(nothing)", "i" ->"(noting)", "r" -> (nothing) and only after I pressed "enter" console suddenly displays the whole word "air", works in the same way with more than one words. In reality the user can write whatever he/she wants but the typed down text will appear only after Enter has been pressed.
In my program I use a BufferedReader object to read from the socket:
try( ....some socket stuff....
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);//out is the socket output
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //in is the socket input
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); //that's the standard input, the one from keyboard
while(true){
if (stdIn.ready()){
userInput=stdIn.readLine();
out.println(userInput);
if(userInput.equals("Bye.")) break;
System.out.println("Me: "+userInput);
}
if(in.ready()){
if((serverInput= in.readLine())!=null){
System.out.println("Stranger: "+serverInput);
}
}
In my opinion that methods - ready and readline() - probably bug the console. It seems a little bit weird for me but it's Java and I'm not very skilled.
Apart from that the chat works like charm - it sends and receives properly. The read-receive-input script is exactly the same and on the client side. When you're typing a message nothing will show up in console but it actually is there and on Enter it displays, it's not a delay, it's influenced by Enter.
This is not possible to do in java.
At least not with platform independent way.
What you are trying to do is, read character by character, without pressing enter key.
But the console on os itself by default is in buffered line mode.
So, only solution is to put your console on raw mode (line editing bypassed and no enter key required), making it platform dependent.
Edit : Your description says character reading, and your code is doing something else by the way.

Issue with loop and BufferedReader

I'm getting an strange issue in a loop that is reading a BufferedReader and never ends...
This is the code:
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int b;
StringBuilder buff = new StringBuilder();
while ((b = in.read()) != -1 ) {
buff.append((char) b);
}
System.out.println(buff.toString());
But never arrives to the last line to print buff.toString().
There's anything wrong in this code?
Thanks.
Can you try changing the while condition like this.
while ((b = in.read()) > -1 ) {
buff.append((char) b);
}
Your loop is trying to read until EOF (that is the only reason for an input stream/reader to return -1 for the read() method).
The problem is that your HTTP connection (and your socket) might be left open (for a while), also leaving your input stream/reader open. So instead of reaching the end condition for your loop, the in.read() call will just block, waiting for input.
If you control the "other side" of the connection, you could close it, to see what happens. But I doubt that would work for the use case in general. Instead, you need to parse the message according to the HTTP protocol (see HTTP/1.1 RFC2616).
If you only need to parse the headers, then you could use your BufferedReader, and read only full lines, until you find an empty line. This will work, because HTTP uses linefeeds (linefeed being CRLF in this case) after each header name/value pair, and end the header part with exactly two linefeeds. Everything after that will be the message body.
PS: This is the easy/happy case. Note that a single connection/socket may be re-used for multiple HTTP requests/responses. You may have handle this as well, depending on your requirements.

Reading parts of a text file

EDIT: I guess this thread can be closed, since all my questions have been answered! Thanks to everyone who helped me!
EDIT: I stumbled upon an error at openFileInput("myfilename.txt");. This is the error: The method openFileInput(String) is undefined for the type Game. I read an answer here: Android File I/O openFileInput() undefined, but must admit that I don't quite understand it...
I'm trying to read parts of a text file, till the token ";". This is the code I wrote:
InputStream instream = openFileInput("myfilename.txt");
String line=null;
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader buffreader = new BufferedReader(inputreader);
while((line=buffreader.readLine())!=null){
String[] parts=line.split(";");
int intOne = Integer.parseInt(parts([0]);
int intTwo = Integer.parseInt(parts([1]);
String strLine = parts([3]);
}
public static void Start(){
while(there is text in the file){
// read first line till ';';
// name that variable intOne;
// read first line after ';' till next ';';
// name that variable intTwo;
// read next line, declare as strLine;
// System.out.println(strLine);
}
}
Beneath it is the idea of what it should do. But I have some questions:
Am I right to say that the String[] parts is an array?
I want to have a bigger file, but read only 3 lines per loop. Or could I, when I have a file of 100 lines, read that all at once, then recall them from the parts[]? Or would that take way too much time?
Where should the text file be? When I'm testing in Eclipse, in the project folder? And when I export it inside the jar?
Hope someone can answer my questions!
(My source is: Read specific string from each line of text file using BufferedReader in java, all credits to Gilbert Le Blanc!)
EDIT: When I do this in the file:
Hello,
I am coding;
Will the pars[0] be Hello,, because that's one line, or Hello, I am coding? And will it take the enter with it?
Another EDIT:
I wish to create some sort of textbased RPG engine, where you only have to edit the text file, to change the story. For example (in the text file):
30;60; //Score needed for this piece of the story
Hello!; // The text
Hi!;5; // The first possible answer; the score you'll get when you answer this
Shut up!;-5; // The second possible answer; the score you'll get when you answer this
What you rly want is reading one char after another. I used some nice BufferedSegmentReader from the framework Smooks, which could be interesting for you. Look at the sourcecode here:
http://grepcode.com/file/repo1.maven.org/maven2/org.milyn/milyn-smooks-all/1.5/org/milyn/edisax/BufferedSegmentReader.java
It reads characters one after another from a stream and puts it into a StringBuffer. There are delimiters to indicate when one "segment" is done reading, and after that you can work with this segment till you tell the BufferedSegmentReader to move on.
I think this rly suits your case and is an approach you are looking for.

Java - Stuck when reading from inputstream

Hello I am currently working with sockets and input/output streams. I have a strange problem with my loop I use to send bytes. For some reason it get stuck when it tries to read from the inputstream when it is supposed to stop. Does anyone have any idea whats wrong?
int bit;
final byte[] request = new byte[1024];
if (response instanceof InputStream)
{
while ((bit = response.read(request)) > 0) { // <-- Stuck here
incoming.getOutputStream().write(request,0,bit);
incoming.getOutputStream().flush();
}
}
incoming.close();
InputStream.read blocks until input data is available, end of file is detected, or an exception is thrown.
You don't catch the exception, and don't check for EOF.
What I've done in the past to leave each side open is to add a termination character to the end of each message that you wouldn't expect to see in the message. If you are building the messages yourself then you could use a character such as a ; or maybe double pipes or something ||. Then just check for that character on the receiving end. Just a workaround. Not a solution. It was necessary in my case but may not be for you.

Categories