I want to read and handle a stream of String containing single OR multiple commands in one line.
I am currently using InputStream in = socket.getInputStream(); for my inputstream.
Also for handling the input a typical Thread:
public void run() {
String input = "";
try {
int data = 0;
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
input += Integer.toHexString(data);
handleInput(input);
}
try {
sleep(500);
} catch (InterruptedException e) {
break;
}
}
socket.close();
return;
} catch (IOException e) {
main.log("Connection lost...");
main.log(e.toString());
main.stopBTCommunication();
main.startBTServer();
}
}
handleInput() is designed to handle any String given to it and response correctly. The problem with this implementation would be, that handleInput() is called with every byte read from in.read(). I know, that i could use BufferedReader.readLine(), but that would require every incomming command to have "\n" appended to it, which is NOT the case and can't be changed.
I know that
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
is kind of nuisance, but basically it want the Thread to read until nothing new is read, then handle that input and then read again...
EDIT:
So basically, what i need is a non-blocking read().
EDIT2:
How can incoming commands and commandchains look like:
Select Command: "s"
ReadLine Command: "rlXX" whereby X is a Hex Digit
WriteLine Command: "wlXXSSSSSSSS" whereby X and S are Hex Digits
So a commandschain may look like one of the following:
"s"
"srlff" = "s" + "rlff"
"rlffwlbb2e2e2e2erlbb" = "s" + "rlff" + "wlbb2e2e2e2e" + "rlbb"
I don't think you really need a non-blocking read. You need a method that reads the stream byte by byte and translates it into commands as it goes.
Something like:
public void processStream(InputStream in) {
List<Command> commands = new ArrayList<Command>();
while((int c = in.getChar()) != -1 ) {
switch((char)c) {
case 's':
commands.add(new SelectCommand());
break;
case 'r':
commands.add(ReadCommand.buildFromStream(in));
break;
case 'w':
commands.add(WriteCommand.buildFromStream(in));
break;
case ';':
commandEngine.execute(commands);
break;
default:
throw new StreamParseError("unexpected character: " + c);
}
}
}
This assumes that SelectCommand, ReadCommand, WriteCommand are type-compatible with Command.
... with for example ReadCommand.buildFromStream being:
public static ReadCommand buildFromStream(InputStream in) {
if((char)in.read() != 'n') {
throw new StreamParseError("Expect 'l' after 'r'");
}
// bad error checking here - be less lazy in real life.
String hexNum = in.read() + in.read();
int num = Integer.parseInt(hexNum,16);
return new ReadCommand(num);
}
This is very primitive parsing, but it shows the principle. There are well established techniques for more advanced parsing, which you can read up on if you want to.
You could also use a Scanner. Most commonly, Scanner is used with delimiters, but it can also look for regex patterns.
Scanner scanner = new Scanner(stream);
String cmd = "";
while(cmd != "e") { // I made up an "end" command :)
cmd = scanner.findWithinHorizon("(s|rl..|wl.{8}|e)",12);
if(cmd == null) {
// end of input, or badly formed input
break;
}
handleCmd(cmd);
}
You can read in array of bytes like this
int bytesRead = 0;
byte[] buffer = new byte[1024]; // reads up to 1024 byte chunks
while((bytesRead = in.read(buffer)) != -1) {
for ( int i = 0; i < bytesRead; i++ ) {
input += Integer.toHexString(buffer[i]);
}
handleInput(input);
}
The above code calls is the same as your old code that "input" keeps growing and used over and over again to call handleInput(). No sure if this is your intention but it looks suspicious.
Note that you are reading data from a stream. This means that you will have to implement recovery of the commands' structure yourself, i.e. you must at least detect the beginning and end of a command in your own code.
This again leads to another problem: You have no guarantee about how your stream's data is split into "chunks" by the transport layer. You may receive one command plus half a command in one read(buffer) call and then the second half of the command plus some more data in the next read(buffer).
Therefore, what I recommend is that you keep reading data only until you detect the end of one message/command/whatever and then perform handling for only this single message, before reading more incoming data and repeating. Everything else (i.e. dealing with partially received messages) easily becomes messy.
EDIT - With this particular input/output, since you don't have a delimiter, Scanner may not be the way to go here, but if you've got a delimiter between commands, it would be a great option, so I'll keep the answer here in the hopes it might help someone in the future.
Since your example doesn't have a delimiter, I have to get a little bit hack-y to demonstrate scanner's awesomeness, but it should still work for the exact commands you've listed. It would not be a good choice if you expect the command vocabulary to change.
I'd really recommend the use of delimiters if at all possible. It makes life much easier.
I'd look at the Scanner class if I were you.
The Scanner can wrap your input stream, and then scan based on a regex or delimter to grab chunks of input. Then your handleInput() method can operate on chunks (whole commands) rather than individual bytes.
Here's a brief, standalone example:
package com.stackoverflow.q22199860;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.regex.Pattern;
public class ReadStream
{
public static void main(String[] args)
{
Pattern commandPattern = Pattern.compile("s|rl|wl");
String commands = "srlffwlbb2e2e2e2erlbb";
Charset utf8 = StandardCharsets.UTF_8;
try (
InputStream inputStream = new ByteArrayInputStream(commands.getBytes(utf8));
Scanner scanner = new Scanner(inputStream, utf8.name());
) {
scanner.useDelimiter(commandPattern);
while(scanner.hasNext()) {
String command = scanner.next();
if (command.isEmpty()){
//s
System.out.println("s" + command);
} else if (command.length() == 2) {
//rl
System.out.println("rl" + command);
} else if (command.length() == 10) {
//wl
System.out.println("wl" + command);
}
}
}
catch (IOException e)
{
System.err.println("Error Reading Stream");
}
}
}
The output from this is:
s
rlff
wlbb2e2e2e2e
rlbb
Related
I'm trying to implement an interruptible readline method [1] in Java , because the standard routine (using a buffered reader around System.in) isn't. I've come up with a routine that works pretty well on Linux, but when you run it in Windows-land, the key-presses are not echoed to the console until the user presses enter - gah!
After some experimenting, it seems the key-presses are only echo'd if there's a blocking call to System.in.read() while the user types.
Does anyone know if this is fixable? I tried to reflect my way in to using the private java.ui.Console#echo method, but it didn't seem to do anything. My next port of call will be to have a look at the JNA API and see if I can get direct access to the console from there.
1 - For reference, here's my interruptible readline implementation. I capture ctrl-c and interrupt the thread that's calling readline - handled elsewhere, working, and probably not relevant for this example
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
public class EchoTest {
private static final long MILLIS_BETWEEN_STDIN_CHECKS = 10;
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("Type something");
// on windows, there's no echo until enter, dammit!
String input = readline(System.in);
System.out.println("Hello, " + input);
}
/**
* Read a line of input from an input stream, presumably stdin.
*
* #param stdin An InputStream to read a line from.
*
* #return the string that was read, with the line terminator removed.
*
* #throws IOException if there was an io error reading from stdin
* #throws InterruptedException if the thread was interrupted while waiting to receive keypresses
*/
public static String readline(InputStream stdin) throws IOException, InterruptedException {
// we use mark to peek ahead for \r\n
if (!stdin.markSupported()) {
throw new IllegalArgumentException("stdin must support mark");
}
// result is stored in here
StringBuffer stringBuffer = new StringBuffer(512);
// a byte buffer as we read a byte at a time from stdin
byte[] bytes = new byte[64];
// number of bytes we've read in to the buffer
int bytesRead = 0;
while (true) {
// check whether read should block
if (stdin.available() > 0) {
int byteRead = stdin.read();
if (byteRead == -1) {
// end of stream - not expected for readline
throw new EOFException();
}
// check for line ending character sequences, we need to detect \r, \n or \r\n
if (byteRead == '\n') {
// we're done!
break;
} else if (byteRead == '\r') {
// we're done, but we might need to consume a trailing \n
if (stdin.available() == 0) {
// nothing is ready, we presume that if \r\n was sent, then they'd be sent as one and the buffer would
// already have the \n
// worst case, the next call to readline will exit with an empty string - if this appears to happen, we
// could detect a \n being in stdin at the start and drop it on the floor
break;
} else {
// there is a byte there - mark our position and check if it's \n
stdin.mark(1);
if (stdin.read() == '\n') {
// it is we're done
break;
} else {
// it isn't \n, reset position for the next call to readline or read
stdin.reset();
break;
}
}
} else {
bytes[bytesRead++] = (byte)byteRead;
// flush buffer if it's full
if (bytesRead == bytes.length) {
stringBuffer.append(new String(bytes, 0, bytesRead));
bytesRead = 0;
}
}
} else {
if (Thread.interrupted()) {
throw new InterruptedException();
} else {
Thread.sleep(MILLIS_BETWEEN_STDIN_CHECKS);
}
}
}
stringBuffer.append(new String(bytes, 0, bytesRead));
return stringBuffer.toString();
}
}
I'm using the class DataInputStream to read from a Socket. I must use the readByte (not readLine) because the input does not necessarily in String format. The problem is I must wait the end of the stream to call a function and I couldn't detect it.
The code:
reader = new DataInputStream(socket.getInputStream());
byte dt;
String cmd = "";
while( (dt = reader.readByte()) >= 0){
cmd += (char)dt;
if( /* end of the stream reached */ ){
processInput(cmd);
}
}
System.out.println("End of the loop");
The problem is I don't know how to write this if. And, the end of the loop is not being reached when the Stream ends, the proof of this is that the phrase "End of the loop" is never being printed, so it is just stuck on the loop
This is documented at readByte()
Throws:
EOFException - if this input stream has reached the end.
So in order to see end of file, you must use try/catch
try {
while(true){
cmd += (char) reader.readByte();
}
} catch (EOFException e) {
// handle EOF
}
/* end of the stream reached */
processInput(cmd);
System.out.println("End of the loop");
An alternative would be to use one of the read() functions, which return -1 when reaching end of file, e.g.
int dt;
while ((dt = reader.read()) >= 0) {
// ...
}
Using one of the other read(...) functions could be more efficient, since they return a buffer full of input.
For a school project I am trying to create a terminal in Java. The terminal works in the following way:
User types a command
Program grabs command and replaces <command> with the command in the string
/bin/bash -c "cd current/directory/; <command>; echo kjsfdjkadhlga; pwd
Program starts the process created via a ProcessBuilder object
Program spawns a thread that reads from stdout and stderr
Program continues looking for user input, and if the command is done running, then whatever the user entered is run as a command, otherwise it is fed to the currently running command as input.
As output is generated, program looks through the output for the kjsfdjkadhlga string so it knows when the user's command is done being run, and then grabs the remaining output and stores it as the current path that the user is at.
How this works/reasons for everything:
In order to avoid myself having to implement my own input parser to handle things like multiple commands on a line, IO redirection, and whatnot to work with the ProcessBuilder, I just essentially convert the command to a bash script and let bash execute it.
Since every process executes only a single command (or whatever it was given at the time of creation, which is a single user command in this case) then terminates, no process specific information is stored, such as the current working directory. To transfer that information, I call pwd after the user's command and then in the process of the next command, but before the user's command is run, I cd to that directory, effectively allowing the value of $PWD to persist between processes.
The Problem:
It all works well, except for when user interaction is required. If the user just types cat, it is supposed to wait for a line of user input, then print it, then wait for a line of user input, then print it, and repeat forever (I don't handle Crtl+C yet...). However, what actually happens is that the terminal waits for a line of user input, then prints it, then terminates without waiting for more input.
What I have tried:
Currently, I provide input to the command being run with:
BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
stdin.write(input);
stdin.newLine();
stdin.close();
If instead of calling close(), I call flush(), then cat ends up waiting for user input and not doing anything until I terminate my Terminal program, at which point it then prints everything the user had input.
It appears that the flush() function doesn't actually do anything. A Stack Overflow question mentioned using the raw OutputStream and calling write() instead of using a BufferedWriter. However, that has the same effect. In the OutputStream documentation for flush(), it states that "The flush method of OutputStream does nothing."
I have also tried using a BufferedOutputStream, but the documentation says that its flush function simply forces the buffered data to be written to the underlying OutputStream, which doesn't change the fact that the OutputStream is not flushing its stream.
This question seems to be the most promising, but I couldn't get it to work when implementing it. It may be because I am on Mac OS instead of Windows.
Does anybody know how to do this if keeping stdin open long enough to submit multiple lines of input is possible, or if I am going about it wrong?
Code
main()
Terminal terminal = new Terminal();
Scanner in = new Scanner(System.in);
while (in.hasNextLine())
{
String line = in.nextLine();
terminal.sendInput(line, terminal);
}
terminal.sendInput() called by main
// ProcessReaderDelegate implements functions called when receiving output on stdout, stderr, and when the process terminates.
public int sendInput(String text, ProcessReaderDelegate delegate)
{
if (processes.size() > 0)
{
processes.get(0).sendInput(text); // Is a ProcessReader object
return 1;
}
run(text, delegate); // runs the given text as the <command> text described above
return 2;
}
ProcessReader's sendInput() called by terminal.sendInput()
public boolean sendInput(String input)
{
try
{
// stdin and process are a instance fields
// tried this and doesn't seem to work (with either flush or close)
stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
stdin.write(input);
stdin.newLine();
stdin.close();
// tried this and doesn't seem to work (with either flush or close)
//BufferedOutputStream os = new BufferedOutputStream(process.getOutputStream());
//os.write(input.getBytes());
//os.write("\n".getBytes());
//os.flush();
//os.close();
return true;
}
catch (IOException e)
{
System.out.println("ERROR: this should never happen: " + e.getMessage());
return false;
}
}
terminal.run() called by terminal.sendInput()
public void run(String command, ProcessReaderDelegate delegate)
{
// don't do anything with empty command since it screws up the command concatentaion later
if (command.equals(""))
{
delegate.receivedOutput(null, prompt);
return;
}
try
{
// create the command
List<String> list = new ArrayList<String>();
list.add(shellPath);
list.add(UNIX_BASED ? "-c" : "Command : ");
String cmd = (UNIX_BASED ? getUnixCommand(command) : getWindowsCommand(command));
list.add(cmd);
//System.out.println("command='" + list.get(0) + " " + list.get(1) + " " + list.get(2) + "'");
// create the process and run it
ProcessBuilder builder = new ProcessBuilder(list);
Process p = builder.start();
ProcessReader stdout = new ProcessReader(p, delegate, this);
new Thread(stdout).start();
processes.add(stdout);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
ProcessReader.run() executed in thread and reads stdout and stderr
public void run()
{
try
{
boolean hitend = false;
String buffer = "";
while (true)
{
int c;
String text;
// ======================================================
// read from stdout
// read the next character
c = stdout.read();
// build the string
while (c != -1) // while data available in the stream
{
buffer += (char)c;
c = stdout.read();
}
// send the string to the delegate
if ((!hitend) && (buffer.length() > 0))
{
// END_STRING is the "kjsfdjkadhlga" echoed after the command executes
int index = buffer.indexOf(END_STRING);
if (index >= 0)
{
hitend = true;
text = buffer.substring(0, index);
buffer = buffer.substring(index + END_STRING.length());
if (outputDelegate != null)
{
outputDelegate.receivedOutput(process, text);
}
}
else
{
for (int i = END_STRING.length() - 1; i >= 0; i--)
{
index = buffer.indexOf(END_STRING.substring(0, i));
if (i == 0)
{
index = buffer.length();
}
if (index >= 0)
{
text = buffer.substring(0, index);
buffer = buffer.substring(index + i);
if (outputDelegate != null)
{
outputDelegate.receivedOutput(process, text);
}
}
}
}
}
// ======================================================
// read from stderr
// read the next character
c = stderr.read();
text = ""; // slow method; make faster with array
// build the string
while (c != -1) // while data available in the stream
{
text += (char)c;
c = stderr.read();
}
// send the string to the delegate
if ((text.length() > 0) && (outputDelegate != null))
{
outputDelegate.receivedError(process, text);
}
// ======================================================
// check if the process is done (and hence no more output)
boolean done = false;
try
{
int value = process.exitValue();
done = true; // if got to this point, then process is done
// read the ending environment variables
Map<String, String> env = new HashMap<String, String>();
String[] words = buffer.split(" ");
env.put(ENV_WORKING_DIR, words[0]);
if (envDelegate != null)
{
envDelegate.processTerminatedWithEnvironment(process, env);
}
// end the process
outputDelegate.processEnded(process);
stdout.close();
stderr.close();
break;
}
catch (Exception e) {System.out.println(e.getMessage());} // no exit value --> process not done
if (done) // just on the off chance that closing the streams crashes everything
{
break;
}
}
}
catch (IOException e)
{
System.out.println("ERROR: ProcessReader: " + e.getMessage());
}
}
Note: I understand that the console is for debugging and games should use GUI. This is for testing/experience
I'm writing a game that runs at 60fps. Every update, I check to see if the user has entered a String command. If so, it gets passed through, but if not, null is paas through, and the null is ignored.
Scanner is out of the question, since hasNext(), the method used to see if there is data to read, can potentially block and causes problems.
I've tried using BufferedReader.ready(). Not only did I have problems (never returned true), but I've read that it's not recommended for a few reasons.
BufferedReader.available() always returned 0, which in the documentation, it state's that InputStream.available() will always return 0 unless overriden. Here is my attempt:
class Game {
public static void main(String[] args) {
InputReader reader = new InputReader(System.in);
int timePerLoop = 1000/30;
Game game = new Game();
while(true) {
long start = System.nanoTime();
game.update(reader.next());
long end = System.nanoTime();
long sleepTime = timePerLoop + ((start - end) / 10000000);
if(sleepTime > 0)
try {
Thread.sleep(sleepTime);
}catch(InterruptedException e) {
e.printStackTrace();
}
else
Thread.yield();
}
}
public void update(String command) {
if(commands != null) {
//handle command
}
//update game
}
}
InputReader.java
public class InputReader {
private InputStream in;
public InputReader(InputStream stream) {
in = stream;
}
public String next() {
String input = null;
try {
while(in.available > 0) {
if(input == null)
input = "";
input += (char) in.read();
}
}catch(IOException e) {
e.printStackTrace();
}
return input;
}
}
InputStream by itself has the same problem as above. I'm not completely sure what type the object stored in System.in, but using available() yields the same results.
I've tried using the reader() from System.console(), but console() returns null. I've read into the subject, and I am not confused why. This is not the way to do it.
The goal is to check the stream to see if it contains data to read, so I can read the data knowing it won't block.
I do not want to use a separate Thread to handle user input, so please don't recommend or ask why.
The input has to be from the console. No new sockets are to be created in the process. I have read a few topics about it, but none of them clearly states a solution. Is this possible?
As you have said yourself, a custom GUI or an additional thread is the correct way to do this. However in absence of that, have you tried using readLine() for example: String inputR = System.console().readLine();
Some alterations to main():
Replace: InputReader reader = new InputReader(System.in); with:
Console c = System.console();
Replace: game.update(reader.next());
with: game.update(c.readLine());
Edit: This thread could also be helpful: Java: How to get input from System.console()
I have one application that prints messages from Test.exe in console .My java program creates one process by executing this Test.exe.
This application prints messages by reading from input-stream of that process.
The problem, that I am facing is,
I have two scenarios:
1) When I double click test.exe, messages("Printing : %d") are printing for every second.
2)But when I run my java application,whole messages are printing at last(not for every second) before terminating Test.exe.If .exe has a very huge messages to print,then it will print those messages(I think whenever buffer becomes full)and flushing will be done.
But how can I print messages same as 1st case.
Help from anyone would be appreciated. :)
Here is the code for this Test.exe.
#include <stdio.h>
#include <windows.h>
void main(void)
{
int i=0;
while (1)
{
Sleep(500);
printf("\nPrinting : %d",i);
i++;
if (i==10)
//if(i==100)
{
return 0;
}
}
}
And my Java application is below:
public class MainClass {
public static void main(String[] args) {
String str = "G:\\Charan\\Test\\Debug\\Test.exe";
try {
Process testProcess = Runtime.getRuntime().exec(str);
InputStream inputStream = new BufferedInputStream(
testProcess.getInputStream());
int read = 0;
byte[] bytes = new byte[1000];
String text;
while (read >= 0) {
if (inputStream.available() > 0 ) {
read = inputStream.read(bytes);
if (read > 0) {
text = new String(bytes, 0, read);
System.out.println(text);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Is it possible in reverse order.If I input some text from console,Java should read and pass that String to .exe(or testProcess).How .exe scan something from Java program.
Could anyone help me..
Given that you're trying to print stdout from that process line by line, I would created a BufferedReader object using the process' input stream and use the readLine() method on that. You can get a BufferedReader object using the following chain of constructors:
BufferedReader testProcessReader = new BufferedReader(new InputStreamReader(testProcess.getInputStream()));
And to read line by line:
String line;
while ((line = testProcessReader.readLine()) != null) {
System.out.println(line);
}
The assumption here is that Test.exe is flushing its output, which is required by any read from the Java side. You can flush the output from C by calling fflush(stdout) after every call to printf().
If you don't flush, the data only lives in a buffer. When considering performance, it's a trade-off, how often you want the data to be written vs. how many writes / flush operations you want to save. If performance is critical, you can consider looking into a more efficient inter-process communication mechanism to pass data between the processes instead of stdout. Since you are on Windows, the first step might be to take a look at the Microsoft IPC help page.
Seems to have something to do with not flushing. I guess it's on both sides - The C library you use seems to only automatically flush output when writing to a terminal. Flush manually after calling printf.
On the Java side, try reading from a non-buffered stream.