Printing to both the console and to a file - java

I am running a program with many classes, with one driver to run all these classes. When I run the driver, the output prints on the console just fine, but I also need the exact output from the console to be printed to a file.
However, I can't seem to get the console output to print to a file. I have tried the suggestion here
How to write console output to a txt file
By doing this
import java.io.FileOutputStream;
import java.io.PrintStream;
public class Compiler {
public static void main(String args[]){
try {
Parse parser = new Parse();
SemanticAnalyzer sAnalyzer = new SemanticAnalyzer();
String parserfile= parser.parsefile(args[0]);
sAnalyzer.semanticAnalysis(parserfile);
PrintStream out = new PrintStream(new FileOutputStream("output.txt"));
System.setOut(out);
} catch (Exception e) {
e.printStackTrace();
}
}
}
but the file still comes out blank (perhaps because the print statements are in other files?).
Does anyone have any ideas?

Create a method that you'll use throughout your code when outputting anything that prints to both streams:
private void output(String text, PrintStream ps1, PrintStream ps2) {
ps1.println(text);
ps2.println(text);
}
And call it from within the code:
PrintStream ps = new PrintStream(new FileOutputStream("output.txt"));
output("text1", System.out, ps);
output("text2", System.out, ps);
output("text3", System.out, ps);
ps.close();

I'm sure this will be answered before I finish typing... however what's happening here is you're redirecting the (default) output stream from the console to a file. If you want to print to both locations you would need to have a PrintStream that actually logs to both locations. (Or you can go look up a logging solution--there are several). However, in the interest of being mildly academic about it:
http://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html
You can implement a PrintStream or OutputStream (probably the better choice) that does this by implementing the interfaces and logging to both the file and console in each case (yikes!).
The easier method, which was explained above by #Voicu but feels a bit misguided is to have a method that replaces System.out(); calls by creating a new method that specifies those streams as part of the output. You could easily create a static method to get around this:
//Redirect via a method
public static PrintStream FILE = new PrintStream(new FileOutputStream("output.txt"));
public static void log(String x)
{
FILE.println(x);
System.out.println(x);
}
Now a terrible, but functional solution, would look something like this:
public static class DualStream extends PrintStream
{
private PrintStream out;
private PrintStream file;
public DualStream(File file, PrintStream out) throws FileNotFoundException
{
super(file);//I'm being SUPER lazy/hacky here
this.out = out;
this.file = new PrintStream(file);
}
//... through all the methods I want to use...
public void println(String x) {
out.println(x);
file.println(x);
}
}
public static void main(String ... args) throws FileNotFoundException
{
DualStream out = new DualStream(new File("output.txt"), System.out);
System.setOut(out);
System.out.println("This is a test");
}
Now this is terrible code, first I'm violating my constructors contract to make this work but it does work. I don't recommend doing this at all, I just wanted to prove it "can be done" if you really need it. The correct approach is to use one of the many loggers out there, or frankly, redirect the output on the command line to where you want it.
What you want in this case is to use the operating system or the server you're running on:
(how to redirect a output of a command to two files)
This does EXACTLY what you want but allows the user to log as needed. If you don't want to log using a logging system (Log4J, Logging package, etc...) then I'd leave it up to your users and just use err/out rather than overthinking it. java -jar myjar.jar > log.txt

Related

Execute Jar file in IDE and get the output (String)? [duplicate]

This question already has answers here:
Execute .jar file from a Java program
(10 answers)
Closed 6 years ago.
Is it possible to execute a Jar file on my IDE (IntelliJ) to get the output string for my own purpose on the project that I have?
I know that we can make system calls, but in this case I want to add a Jar file on my project and execute it whenever I want it.
For example: I have a project on IntelliJ, one of my classes (on this project) needs to get the output by running the Jar file (which is on my project).
On my terminal, I would do something like java -jar <jar_file>.jar <file>.asm and this would output a result to my terminal.
And I want to get that output from this command on my Java Class.
Your Jar file returns an output string, so I assume, it's main-method could look like:
public static void main(String[] args) {
System.out.println("output string");
}
And now, if you want to use this "output string" string in your own class, you could do it like this:
public class YourClass {
...
public String getOutputStringFromJar() {
String s = ""; // or = null;
try {
Process p = Runtime.getRuntime().exec("java -jar full/path/to/your/Jar.jar full/path/to/fibonacci.asm");// just like you would do it on your terminal
p.waitFor();
InputStream is = p.getInputStream();
byte b[] = new byte[is.available()];
is.read(b, 0, b.length); // probably try b.length-1 or -2 to remove "new-line(s)"
s = new String(b);
} catch (Exception ex) {
ex.printStackTrace();
}
return s;
}
...
}
Now you have the method, that returns the output string, and you can use it however you want, and you know how to execute a Jar file from your project whenever you want
Your ask is not precise, but if i understand what you're doing, you run the Mars.jar with .asm file in param, and you got an output like in the this link with Fibonacci numbers
and now you want to get the Fibonacci numbers in your program? if that is what you need, i would suggest you to decompile the jar to understand his content
When you do so, you'll see that the main class in the jar is like this
public class Mars {
public static void main(String[] args) {
new mars.MarsLaunch(args);
}
}
so simply when you add the jar to your class path, you need to do somthing like this
public static void main(String[] args) throws FileNotFoundException {
// this will redirect your system output to a file named output.txt
PrintStream out = new PrintStream(new FileOutputStream("output.txt"));
System.setOut(out);
String [] myAsmFile = {"C:/produits/Fibonacci.asm"};
new mars.MarsLaunch(myAsmFile);
// and then you can read the output.txt file
}
hope this help you

FileWriter issue - unreported IOEXception which must be caught

I've encountered an issue in Java trying to write to a file using FileWriter. Simply declaring FileWriter writer = new FileWriter("filelocation"); yields that there is an unreported IOException which must be caught.
To rectify this, naturally I put my FileWriter within a try-catch block, but that causes an issue with scope. To fix this, I tried declaring the FileWriter before the try catch block and assigning the location within the try catch. After the try catch block when I would like to use the FileWriter, it tells me it may not have been initialized. I'm not certain how else to handle this, and never encountered this issue in Java 1.7 or likewise.
This is an example of my final situation in case I was unclear;
Scanner userInput = new Scanner(System.in);
FileWriter writer;
try {
System.out.println("Enter the file directory you would like to store in");
String fileLocation = userInput.nextLine();
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Error message");
}
writer.write("Stuff"); //writer may not have been initialized
The good way :
System.console().printf("Enter the file directory you would like to store in");
String location = System.console().readLine();
try (FileWriter writer = new FileWriter (location)) {
writer.write("Stuff");
} catch (IOException e) {
new RuntimeException("Error message", e).printStackTrace();
}
Explanations:
System.console().printf() enable to print message on stdout. System.out may be prefered is having a "console" is not strictly required.
Uses System.console() for console management. Much easier and clearer. Don't forget to allocate a console (ie don't use javaw executable).
Opens stream using try-with-resources statement
printStackTrace() print on stderr the call stack which ease finding error location in code.
I have built a new Exception to attach your error message with the stack trace adds the "catch" location in the stack.
Advices:
Uses byte-stream for file access (ie FileOutputStream). It enables to enforce charset (ie OutputStreamWriter) and buffering (ie BufferedOutputStream or BufferedWriter).
Using byte-stream makes also possible to switch to NIO Channel API.
Uses StandardCharsets to access default (and largely commonly used) charset (Charsets that all JVM implementations must support)
Read The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
call to printStackTrace() isn't really nice and you should quickly introduce a logging system to print messages.
In case of a CLI, have good attention when using logging system to not confuse user about system interactions (ie prompt for user input) and feedbacks (ie progress message)
You say "naturally" you put it within a try-catch block. There's nothing natural about that, since there are two ways to handle it, and the other way is more common:
Handle the exception in a try-catch block.
Don't handle the exception, but declare that your method throws the exception, and allow it to cascade up the call stack.
Your code looks like it's in a main method, so you could add throws IOException:
public static void main(String[] args) throws IOException {
In your particular case, however, you're getting the file location from a user prompt, so rather than letting the program die with an error, the appropriate thing would be to tell the user about the error and prompt for a new name.
Also, remember to close your resources.
public static void main(String[] args) throws IOException {
Scanner userInput = new Scanner(System.in);
FileWriter writer;
do {
System.out.println("Enter the file name you would like to store in");
String fileLocation = userInput.nextLine();
if (fileLocation.trim().isEmpty())
return; // Exit program when user pressed enter with a name
try {
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Cannot write to file: " + e);
writer = null;
}
} while (writer == null);
try {
writer.write("Stuff"); //writer may not have been initialized
} finally {
writer.close();
}
}
The write and the close can still technically throw an error (e.g. disk full), which we allow to cascade and kill the program.

Preventing the JVM from writing to System.out or reading from System.in

Is there a way under the JVM to (temporarily) prevent complete access to System.out, System.in and System.err ?
After creating a blank policy which grants no permission at all, I want to execute some work in the function below. I would like calls to System.out.println and the like to fail, but they don't. Is there something I can do or am I being a little too much of a control freak ?
EDIT #1: Following MrPixelDream's suggestion to use System.setOut, I am keeping the permissions to a minimum to make sure code within run() cannot also call System.setOut or fool around with java.io.FileDescriptor.out.
EDIT #2: Also, since rogue code could have simply executed standardOutput.println, I prefered not to keep a reference to System.out around at all and set it back using java.io.FileDescriptor.out.
// Create blank permissions that barely allow executing code
java.security.Permissions perm = new java.security.Permissions();
// CodeSource domain for which these permissions apply (all files)
java.security.CodeSource code = new java.security.CodeSource(new java.net.URL("file:/*"),
null);
// ProtectionDomain
java.security.ProtectionDomain domain = new java.security.ProtectionDomain(code, perm);
// AccessControlContext
java.security.ProtectionDomain[] domains = new java.security.ProtectionDomain[1];
domains[0] = domain;
java.security.AccessControlContext context =
new java.security.AccessControlContext(domains);
// DON'T keep reference to standard output, it could be used directly
// PrintStream standardOut = System.out;
// Redirect output to dummy stream
System.setIn(new ByteArrayInputStream(new byte[0]));
System.setOut(new PrintStream(new ByteArrayOutputStream()));
System.setErr(new PrintStream(new ByteArrayOutputStream()));
// Do an action, subject to the given security context
java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
public Void run() {
// Do some work, side effects and all, but no I/O whatsoever
System.out.println("Will not print !");
// Try to fool around System.out with direct access from file descriptors (0, 1, 2)
java.io.PrintStream myOut =
new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out));
// Missing permission java.lang.RuntimePermission "setIO"
// Will throw java.security.AccessControlException
System.setOut(myOut);
// Missing permission java.lang.RuntimePermission "writeFileDescriptor"
myOut.println("Will throw java.security.AccessControlException !");
}
}, context);
// Now set back the old streams to have output again
System.setIn(new java.io.FileInputStream(java.io.FileDescriptor.in));
System.setOut(
new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out)));
System.setErr(
new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.err)));
The answer of Elliott Frisch will do the trick, but you cant receive output after doing it. If you intend to have output muted just temporarily, use this code:
public class RedirectedOutput {
public static void main(String[] args) {
// Save the old output stream to have the chance to set it back later
InputStream standardIn = System.in;
PrintStream standardOut = System.out;
PrintStream standardErr = System.err;
// Set useless streams
System.setIn(new ByteArrayInputStream(new byte[0]));
System.setOut(new PrintStream(new ByteArrayOutputStream()));
System.setErr(new PrintStream(new ByteArrayOutputStream()));
// Will not be shown
System.out.println("Hello World");
// Now set back the old streams to have output again
System.setIn(standardIn);
System.setOut(standardOut);
System.setErr(standardErr);
// Will be shown again
System.out.println("Finally we got the Hello");
}
}
You can try out this example which should be fully runnable. It should be self-explaining. You are using setIn(), setOut() and setErr() to change the streams and you save it before to be able to set it back.
But if you don't need any output, you are better with Elliott's code because I guess it's better for resources.
I do not believe there is a way to do this temporarily, but you can prevent them writing or reading until the JVM is restarted by close()ing them with something like,
public static void main(String[] args) {
try {
System.in.close();
} catch (IOException e) {
e.printStackTrace();
}
System.err.close();
System.out.close();
System.out.println("Must not print !");
}
And there is no output.

How to write "enter key pressed" to a stream?

Sorry for this odd-sounding title...
I have the following situation: I want my Java program to interact with an external console. In order to "send" the individual commands to that console, I need to simulate what would be an "enter key pressed" on a normal console. To clarify what I want, imagine mysql had no other API and I would need to interact via console. Although this is not my actual problem, it is close enough.
I have the following code:
String command = "/usr/local/mysql/bin/mysql";
Process child = Runtime.getRuntime().exec(command);
StreamGobbler gobbler = new StreamGobbler(child.getInputStream());
gobbler.start();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(child.getOutputStream()));
out.write("help");
// here enter key needs to be pressed
out.flush();
// out.close();
If the call to out.close() is executed, everything is fine. But of course, this way I can only send a single command, which is not what I want. But if out.close() is omitted, the other program never executes the command. My guess is that it still waits for the command to "finish", which on a normal console would be done by pressing enter. out.write(System.getProperty("line.separator")); and out.newLine(); (which are the same) do not solve the problem, neither does out.write("\r\n"); and out.write((char) 26); (EOF).
Of course, it might be, that I am doing it completely wrong (i.e., wrong approach). Then I would appreciate a pointer into the right direction...
Any help on this highly appreciated.
The following code works fine on both Windows 7 using Java 1.6.0_23 and on Ubuntu 8.04 using Java 1.6.0_22:
public class Laj {
private static class ReadingThread extends Thread {
private final InputStream inputStream;
private final String name;
public ReadingThread(InputStream inputStream, String name) {
this.inputStream = inputStream;
this.name = name;
}
public void run() {
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(inputStream));
for (String s = in.readLine(); s != null; s = in.readLine()) {
System.console().writer().println(name + ": " + s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
String command = "psql -U archadm arch";
final Process child = Runtime.getRuntime().exec(command);
new ReadingThread(child.getInputStream(), "out").start();
new ReadingThread(child.getErrorStream(), "err").start();
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(child.getOutputStream()));
out.write("\\h");
out.newLine();
out.flush();
out.write("\\q");
out.newLine();
out.flush();
}
}
newLine() is the same as writing the platform line separator. As one would expect, it prints help preceded with "out: ", then exits. If I don't send "\q", it doesn't exit (obviously) but still prints help. Using "\r\n" or "\r" instead of the platform line separator doesn't look like a good idea to me, because such command-line utilities will usually detect that they don't get input from the terminal and assume it is in the native text format (think "psql < script.sql"). Good software should properly detect and accept all reasonable line endings though.
What about out.write((char) 13)? See this Wikipedia article. I don't have enough code to test this for you.
You also might want to try looking at this API
http://download.oracle.com/javase/6/docs/api/java/io/Console.html
From my experience, I've never tried doing anything more than running one process from the Process API. It seems like you want to enter multiple commands I think this API might let you do that.
EDIT: Found a tutorial on it to help you further.
http://download.oracle.com/javase/tutorial/essential/io/cl.html
Hope this helps,

Java, Junit - Capture the standard input / Output for use in a unit test [duplicate]

This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 8 years ago.
I'm writing integration tests using JUnit to automate the testing of a console based application. The application is homework but this part isn't the homework. I want to automate these tests to be more productive -- I don't want to have to go back and retest already tested parts of the application. (Standard reasons to use Unit tests)
Anyway, I can't figure out or find an article on capturing the output so that I can do assertEquals on it nor providing automated input. I don't care if the output/input goes to the console/output pane. I only need to have the test execute and verify the the output is what is expected given the input.
Anyone have an article or code to help out with this.
Use System.setOut() (and System.setErr()) to redirect the output to an arbitrary printstream - which can be one that you read from programmatically.
For example:
final ByteArrayOutputStream myOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(myOut));
// test stuff here...
final String standardOutput = myOut.toString();
The System class has methods setIn(), setOut() and setErr() that allow you to set the standard input, output and error streams, e.g. to a ByteArrayOutputStream that you can inspect at will.
Here is the solution in place of ByteArrayOutputStream. It does not add anything to the idea of System.setOut. Rather, I want to share the implementation that is better than capturing everything into ByteArrayOutputStream. I prefer to capture only selected information and let all log messages to appear in the console as they are logged rather than capturing everything into a balckbox (of which size?) for later processing.
/**
* Once started, std output is redirected to this thread.
* Thread redirects all data to the former system.out and
* captures some strings.*/
static abstract class OutputCaputre extends Thread {
// overrdie these methods for System.err
PrintStream getDownstream() { return System.out;}
void restoreDownstream() { System.setOut(downstream);}
// will be called for every line in the log
protected abstract void userFilter(String line);
final PrintStream downstream;
public final PipedInputStream pis;
private final PipedOutputStream pos;
OutputCaputre() throws IOException {
downstream = getDownstream();
pos = new PipedOutputStream();
pis = new PipedInputStream(pos);
System.setOut(new PrintStream(pos));
start();
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
// once output is resotred, we must terminate
while (true) {
String line = br.readLine();
if (line == null) {
return;
}
downstream.println(line);
userFilter(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void terminate() throws InterruptedException, IOException {
restoreDownstream(); // switch back to std
pos.close(); // there will be no more data - signal that
join(); // and wait until capture completes
}
};
Here is an example of using the class:
OutputCaputre outputCapture = new OutputCaputre() {
protected void userFilter(String line) {
downstream.println("Capture: " + line);
}
};
System.out.println("do you see me captured?");
// here is your test
outputCapture.terminate(); // finally, stop capturing

Categories

Resources