Java: Printing to the console and to a file

2019-09-15 19:20发布

I have a bit of a problem

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?

标签: java file
2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-09-15 19:48

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

查看更多
霸刀☆藐视天下
3楼-- · 2019-09-15 19:54

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();
查看更多
登录 后发表回答