I'm new to programming, and I'm making an app that only runs in the command-line. I found that I could use a BufferedReader to read the inputs from the command-line.
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String Input = "";
while (Input.equalsIgnoreCase("Stop") == false) {
Input = in.readLine();
//Here comes the tricky part
}
in.close();
What I'm trying to do now is to find a way to create different "commands" that you could use just by typing them in the command-line. But these commands might have to be used multiple times. Do I have to use some kind of Command design pattern with a huge switch statement (that doesn't seem right to me)? I'd like to avoid using an extra library.
Can someone with a bit more experience that me try to help me?
You could try something like this:
public static void main(String[] args) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String input = "";
try {
while (!input.equalsIgnoreCase("stop")) {
showMenu();
input = in.readLine();
if(input.equals("1")) {
//do something
}
else if(input.equals("2")) {
//do something else
}
else if(input.equals("3")) {
// do something else
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void showMenu() {
System.out.println("Enter 1, 2, 3, or \"stop\" to exit");
}
It is good practice to keep your variables lower cased.
I would also say that !Input.equalsIgnoreCase("stop") is much more readable than Input.equalsIgnoreCase("stop") == false although both are logically equivalent.
If it's just about reading the program parameters you can just add them behind the Java application call and access them through your args argument of your main method. And then you can loop through the array and search for the flags your program accepts.
Related
This is not the same as this question: JUnit: How to simulate System.in testing?, which is about mocking stdin.
What I want to know is how to test (as in TDD) that a simple Java class with a main method waits for input.
My test:
#Test
public void appRunShouldWaitForInput(){
long startMillis = System.currentTimeMillis();
// NB obviously you'd want to run this next line in a separate thread with some sort of timeout mechanism...
// that's an implementation detail I've omitted for the sake of avoiding clutter!
App.main( null );
long endMillis = System.currentTimeMillis();
assertThat( endMillis - startMillis ).isGreaterThan( 1000L );
}
My SUT main:
public static void main(String args[]) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter something : ");
String input = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
... test fails. The code does not wait. But when you run the app at the command prompt it does indeed wait.
NB by the way I did also try with setting stdin to sthg else:
System.setIn(new ByteArrayInputStream( dummy.getBytes()));
scanner = new Scanner(System.in);
... this did not hold up the test.
As a much more general rule, static methods (such as main methods) are difficult to test. For this reason, you almost never call the main method (or any other static method) from your test code. A common pattern to work around this is to convert this:
public class App {
public static void main(String args[]) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter something : ");
String input = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
}
to this:
public class App {
private final InputStream input;
private final OutputStream output;
public App(InputStream input, OutputStream output) {
this.input = input;
this.output = output;
}
public static void main(String[] args) {
new App(System.in, System.out).start();
}
public void start() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(input));
output.print("Enter something : ");
String nextInput = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now your test becomes this:
#Test
public void appRunShouldWaitForInput(){
ByteArrayOutputStream output = new ByteArrayOutputStream();
// As you have already noted, you would need to kick this off on another thread and use a blocking implementation of InputStream to test what you want to test.
new App(new ByteArrayInputStream(), output).start();
assertThat(output.toByteArray().length, is(0));
}
The key idea is that, when you run the app "for real" i.e. via the main method, it will use the Standard input and output streams. However, when you run it from your tests, it uses a purely in memory input/output stream which you have full control over in your test. ByteArrayOutputStream is just one example, but you can see in my example that the test is able to inspect the actual bytes that have been written to the output stream.
in general: you can't test if your program is waiting until something happens (because you can't test if it waits forever)
what is usually done in such case:
in your case: don't test it. readLine is provided by external library that was tested pretty intensive. cost of testing this is much higher then the value of such test. refactor and test your business code (string/stream operations), not infrastructure (system input)
in general case it's testing concurrent programming. it's hard so ppl usually try to find some useful simplification:
you can just test if output of your program is correct for the input provided in tests.
for some really hard problems above technique is combined with running test thousands times (and forcing thread switching if possible) to detect errors in concurrent programming (violated invariants)
before your test provides an input date, you can test if your program is in correct state (waiting thread, correct field values etc)
in worst case, you can use delay in tests before providing input to be sure, your program waits and uses the input. this technique is often used because it's simple but it's smelly and if you add more tests like that your whole suit gets slower
I want to use an external tool while extracting some data (loop through lines).
For that I first used Runtime.getRuntime().exec() to execute it.
But then my extraction got really slow. So I am searching for a possibility to exec the external tool in each instance of the loop, using the same instance of shell.
I found out, that I should use ProcessBuilder. But it's not working yet.
Here is my code to test the execution (with input from the answers here in the forum already):
public class ExecuteShell {
ProcessBuilder builder;
Process process = null;
BufferedWriter process_stdin;
BufferedReader reader, errReader;
public ExecuteShell() {
String command;
command = getShellCommandForOperatingSystem();
if(command.equals("")) {
return; //Fehler! No error handling yet
}
//init shell
builder = new ProcessBuilder( command);
builder.redirectErrorStream(true);
try {
process = builder.start();
} catch (IOException e) {
System.out.println(e);
}
//get stdout of shell
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//get stdin of shell
process_stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
System.out.println("ExecuteShell: Constructor successfully finished");
}
public String executeCommand(String commands) {
StringBuffer output;
String line;
try {
//single execution
process_stdin.write(commands);
process_stdin.newLine();
process_stdin.flush();
} catch (IOException e) {
System.out.println(e);
}
output = new StringBuffer();
line = "";
try {
if (!reader.ready()) {
output.append("Reader empty \n");
return output.toString();
}
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
return output.toString();
}
if (!reader.ready()) {
output.append("errReader empty \n");
return output.toString();
}
while ((line = errReader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
System.out.println("ExecuteShell: error in executeShell2File");
e.printStackTrace();
return "";
}
return output.toString();
}
public int close() {
// finally close the shell by execution exit command
try {
process_stdin.write("exit");
process_stdin.newLine();
process_stdin.flush();
}
catch (IOException e) {
System.out.println(e);
return 1;
}
return 0;
}
private static String getShellCommandForOperatingSystem() {
Properties prop = System.getProperties( );
String os = prop.getProperty( "os.name" );
if ( os.startsWith("Windows") ) {
//System.out.println("WINDOWS!");
return "C:/cygwin64/bin/bash";
} else if (os.startsWith("Linux") ) {
//System.out.println("Linux!");
return"/bin/sh";
}
return "";
}
}
I want to call it in another Class like this Testclass:
public class TestExec{
public static void main(String[] args) {
String result = "";
ExecuteShell es = new ExecuteShell();
for (int i=0; i<5; i++) {
// do something
result = es.executeCommand("date"); //execute some command
System.out.println("result:\n" + result); //do something with result
// do something
}
es.close();
}
}
My Problem is, that the output stream is always empty:
ExecuteShell: Constructor successfully finished
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
I read the thread here: Java Process with Input/Output Stream
But the code snippets were not enough to get me going, I am missing something. I have not really worked with different threads much. And I am not sure if/how a Scanner is of any help to me. I would really appreciate some help.
Ultimatively, my goal is to call an external command repeatetly and make it fast.
EDIT:
I changed the loop, so that the es.close() is outside. And I wanted to add, that I do not want only this inside the loop.
EDIT:
The problem with the time was, that the command I called caused an error. When the command does not cause an error, the time is acceptable.
Thank you for your answers
You are probably experiencing a race condition: after writing the command to the shell, your Java program continues to run, and almost immediately calls reader.ready(). The command you wanted to execute has probably not yet output anything, so the reader has no data available. An alternative explanation would be that the command does not write anything to stdout, but only to stderr (or the shell, maybe it has failed to start the command?). You are however not reading from stderr in practice.
To properly handle output and error streams, you cannot check reader.ready() but need to call readLine() (which waits until data is available) in a loop. With your code, even if the program would come to that point, you would read only exactly one line from the output. If the program would output more than one line, this data would get interpreted as the output of the next command. The typical solution is to read in a loop until readLine() returns null, but this does not work here because this would mean your program would wait in this loop until the shell terminates (which would never happen, so it would just hang infinitely).
Fixing this would be pretty much impossible, if you do not know exactly how many lines each command will write to stdout and stderr.
However, your complicated approach of using a shell and sending commands to it is probably completely unnecessary. Starting a command from within your Java program and from within the shell is equally fast, and much easier to write. Similarly, there is no performance difference between Runtime.exec() and ProcessBuilder (the former just calls the latter), you only need ProcessBuilder if you need its advanced features.
If you are experiencing performance problems when calling external programs, you should find out where they are exactly and try to solve them, but not with this approach. For example, normally one starts a thread for reading from both the output and the error stream (if you do not start separate threads and the command produces large output, everything might hang). This could be slow, so you could use a thread pool to avoid repeated spawning of processes.
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 know how to use string args to get the input from the command-line, and it is working fine with input = args[0] where my input is java.exe program s1.in
But I need to run a compare program in terminal. So my input must have the "<" symbol. However, then I can't get my input values using input = args[1]. When I type this in, the args.length become 0. Why does this happen?
As an aside, does anyone know how to best search for this kind of term in google? Itthink google does not recognize "<" in the search entry.
Thank you
It's because when you use xyzzy <inputfile, your shell runs xyzzy and "connects" that file to your standard input. It then expects you to read that standard input to get your data - you never see the argument because it's removed from the command line (or, more likely, never added to your argument list).
That's why many programs will process a file if given, otherwise they'll read their data from standard input. And that's exactly what you need to do here.
For doing this, you'll probably want something like:
import java.io.*;
class Test {
public static void main(String args[]) {
InputStreamReader inp = null;
Boolean isStdIn = false;
try {
if (args.length > 0) {
inp = new InputStreamReader(new FileInputStream(args[0]));
} else {
inp = new InputStreamReader(System.in);
isStdIn = true;
}
// Now process inp.
if (isStdIn)
inp.close();
} catch (Exception e) {
System.exit(1);
}
}
}
It selects either the file (if available) or the standard input stream for reading.
Often, the most easy way is to use Scanner:
Scanner scaner = new Scanner (System.in);
I am new to java. I think this is the simplest problem but even i dont know how to solve this problem. I have one text file. In that file i have some words like below :
good
bad
efficiency
I want to add list of words into another by using java program. My output want to be like this
good bad
good efficiency
bad efficiency
How to get this using java program. I tried search for some ideas. But i wont get any idea. Please suggest me any ideas. Thanks in advance.
If you do not want to learn it from scratch I would recommend using the Apache Commons io library.
The FileUtils class has a simple interface to read from and write to a file.
A good place to start learning Java IO would be to look over Sun's Java Tutorials on File IO. If you're looking into how to read in individual lines, I would particularly look at Scanners. And if at some point you're looking to manipulate Strings like this without IO being heavily involved, I'd look at Java's StringBuilder.
import java.io.*;
class Test {
//--------------------------------------------------< main >--------//
public static void main (String[] args) {
Test t = new Test();
t.readMyFile();
}
//--------------------------------------------< readMyFile >--------//
void readMyFile() {
String record = null;
String rec=null;
int recCount = 0;
try {
FileReader fr = new FileReader("c:/abc/java/prash.txt");
FileReader fr1 = new FileReader("c:/abc/java/pras.txt");
BufferedReader br = new BufferedReader(fr);
BufferedReader br1 = new BufferedReader(fr1);
record = new String();
rec = new String();
while ((record = br.readLine()) != null && (rec=br1.readLine())!=null) {
// recCount++;
System.out.print(record +" "+ rec);
//System.out.print(rec);
}
} catch (IOException e) {
// catch possible io errors from readLine()
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
} // end of readMyFile()
} // end of class