12

I found the code below from the internet, works but it doesn't write the printed console to omt.txt, it only writes the System.out.println statements after the second catch block.If you run the code once you will understand what I mean.All I want is to write what is on console to the "omt.txt" file that is all...

After some answers, I see that my question wasn't clear, sorry for that. I want to save console output to omt.txt text file. If on the console "Hello 123" is printed , it should be also in omt.txt file.In other words whatever on the console is printed should be simultaneously written on the om.txt file or can be after the console execution but should be 1-to-1 the same!

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class Wrt_file {

    public static void main(String[] args) {
        System.out.println("THIS is what I see on the console. but not on TEXT file"); 

          File f = new File("omt.txt");
          if(!f.exists())
          {
            try {
                       f.createNewFile();
                } catch (Exception e) {
                    e.printStackTrace();
                }
          }

        try {
                FileOutputStream fos = new FileOutputStream(f);
                PrintStream ps = new PrintStream(fos);
                System.setOut(ps);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("THIS is what I see on the text file, but not on CONSOLE");      

        for (int i=0; i<10; i++){

            System.out.println("Testing");  
        }

    }

}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
Anarkie
  • 657
  • 3
  • 19
  • 46

4 Answers4

24

Updated answer after learning that OP wants to duplicate streams

Since you want to write data in both streams try using TeeOutputStream from Apache Commons. Change your code in second try to

try {
    FileOutputStream fos = new FileOutputStream(f);
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        try {
            fos.flush();
        }
        catch (Throwable t) {
            // Ignore
        }
    }, "Shutdown hook Thread flushing " + f));
    //we will want to print in standard "System.out" and in "file"
    TeeOutputStream myOut=new TeeOutputStream(System.out, fos);
    PrintStream ps = new PrintStream(myOut, true); //true - auto-flush after println
    System.setOut(ps);
} catch (Exception e) {
    e.printStackTrace();
}

Now results from System.out will also be placed in your file.

leventov
  • 14,760
  • 11
  • 69
  • 98
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • I thought it should be possible in java to save the output displayed on console into a text file...This is what I want. – Anarkie Apr 26 '13 at 14:00
  • So it's TeeOutputStream! Was also looking for an OutputStream that I can pipe the stdout to for my answer. This is the best solution. +1 :) – Jops Apr 26 '13 at 14:33
  • 1
    @Ronixus Yeah Apache Commons rules :) – Pshemo Apr 26 '13 at 14:36
  • I tried this : import org.apache.commons.io.output.TeeOutputStream; but got the error "The import org.apache cannot be resolved" how can I import TeeOutputStream ? – Anarkie Apr 26 '13 at 14:44
  • @Anarkie you need to add jars to your classpath. What IDE are you using? – Pshemo Apr 26 '13 at 14:45
  • Eclipse Juno 4.2.2 - Java 1.6 – Anarkie Apr 26 '13 at 14:51
  • 1
    @Anarkie [Here](http://www.wikihow.com/Add-JARs-to-Project-Build-Paths-in-Eclipse-%28Java%29) you have few ways to add jars to your projects. "Adding External JARs" method 2 (you need to have Java view opened) or 3 is what you are looking for: `right click on project` -> `build path` -> `add external libraries`. – Pshemo Apr 26 '13 at 14:53
  • 1
    Download `commons-io-2.4-bin.zip` from [here](http://commons.apache.org/proper/commons-io/download_io.cgi). When you unpack it you will see `commons-io-2.4.jar`. Add it to your project. – Pshemo Apr 26 '13 at 15:07
  • Thanks now I see everything on the console this is good Im very close!But still The first Text "THIS is what I see on the console. but not on TEXT file" is not written on the omt.txt file :( – Anarkie Apr 26 '13 at 15:49
  • 1
    @Anarkie If you want that line to be also in your file then you need to move code that prints it after you change standard output stream to `System.setOut(ps)`. I don't see any way to include to file already printed massages before you redirected output stream. – Pshemo Apr 26 '13 at 16:04
  • That's what I thought so, but wanted to try my luck, this solution is more than enough, I can just move the lines under `System.setOut(ps)` np. Thanks for everything! :) – Anarkie Apr 26 '13 at 16:34
  • Using the above solution, is it possible to conditionally stop writing to the file and then restart by appending? I have a scenario where I want to write to a file, but there are some parts that I want to see only on the console, but do not want them to be written to the file – adbdkb Jun 16 '19 at 19:44
  • @adbdkb "but there are some parts that I want to see only on the console, but do not want them to be written to the file" in that case consider not calling `System.setOut(ps);` because this will replace default `System.out` with `ps`. Use `ps` if you want to write to both console and file, and `System.out` if you want to print only to console. – Pshemo Jun 16 '19 at 23:00
  • @adbdkb OR **before** replacing default output stream (console) with `System.setOut(ps);` store `System.out` like `PrintStream onlyConsole = System.out;`. This way you can use `onlyConsole` to print only to console and then replaced `System.out` to print to both streams. You should probably also be able to juggle `System.setOut(ps);` and `System.setOut(onlyConsole );` to switch them. – Pshemo Jun 16 '19 at 23:02
  • Thanks @Pshemo - I tried the second suggestion and it worked. – adbdkb Jun 18 '19 at 11:59
2

The reason is :

The java.lang.System.setOut() method reassigns the "standard" output stream.

so when you use System.out.println it will print only in the text file

So , if you want to print on the text file and on the console , Try this :

   

    FileOutputStream fos = new FileOutputStream(f);
    PrintStream ps = new PrintStream(fos);
    ps.println("THIS is what I see on the text file, but not on CONSOLE");
    System.out.println("THIS is what I see on the text file, but not on CONSOLE");

        for (int i = 0; i < 4; i++) {

            ps.println("Testing");
            System.out.println("Testing");
        } 
Alya'a Gamal
  • 5,624
  • 19
  • 34
2

My solution to this problem is to simply define your own PrintStream which overrides the methods you are using:

import java.io.FileNotFoundException;
import java.io.PrintStream;

public class DualStream extends PrintStream {
    public PrintStream consoleOutput = null;
    public PrintStream fileOutput = null;

    public DualStream(final PrintStream consoleOutput, final PrintStream fileOutput) throws FileNotFoundException {
        super(fileOutput, true);
        this.consoleOutput = consoleOutput;
        this.fileOutput = fileOutput;
    }

    @Override
    public void println() {
        consoleOutput.println();
        super.println();
    }

    @Override
    public void println(final Object output) {
       consoleOutput.println(output);
        super.println(output);
    }

    @Override
    public void println(final String output) {
        consoleOutput.println(output);
        super.println(output);
    }

    @Override
    public PrintStream printf(final String output, final Object... variables) {
        consoleOutput.printf(output, variables);
        super.printf(output, variables);
        return this;
    }
}

Every method we don't override will default to writting the output to the file only. (To default to console you can switch 1 line in the Constructor or switch both printstreams position in the constructor call)

Now simply define 2 printstreams, one of which will be writting to your file, let's make it a bufferedoutputstream to ensure good performance aswell:

public static void outputFile(final String file) {
    PrintStream CombinedOutput = null;
    try {
        CombinedOutput = new DualStream(System.out, new PrintStream(new BufferedOutputStream(new FileOutputStream(file))));
    } catch (final FileNotFoundException e) {
        e.printStackTrace();
    }
    System.setOut(CombinedOutput);
}
HopefullyHelpful
  • 1,652
  • 3
  • 21
  • 37
1

In System.java, this is the declaration of the out property:

public final static PrintStream out

You'll see that it can only be one PrintSteam object at a time. So it's either the console or the file, but not both.

At this line, you have effectively re-channelled the destination:

System.setOut(ps);

So your output stops displaying on the console.

Jops
  • 22,535
  • 13
  • 46
  • 63
  • I know that the code works and Testing... is written to the text file but Testing.. loop isnt on the java console, the Text printed on the java console is also not in the text file ... what I want is if I print on the console "Hello 123", Hello 123 should be in omt.txt – Anarkie Apr 26 '13 at 13:33
  • Is there not a way to mirror console?I don't think it should be so complicated in java :/ – Anarkie Apr 26 '13 at 13:44
  • What do you mean by `mirror console`? Do you want to print into console and file at the same time? – Pshemo Apr 26 '13 at 13:45
  • Exactly this is what I want...If it is not possible to do at the same time I would like them to display at least the same results... – Anarkie Apr 26 '13 at 13:56