I once wrote this little utility class for exactly this purpose. It is an OutputStream that will split all output across 2 different output streams.
import java.io.IOException; import java.io.OutputStream; public class SplitOutputStream extends OutputStream { private final OutputStream s1; private final OutputStream s2; public SplitOutputStream(OutputStream s1, OutputStream s2) { this.s1 = s1; this.s2 = s2; } public void close() throws IOException { s1.close(); s2.close(); } public void flush() throws IOException { s1.flush(); s2.flush(); } public void write(byte[] b) throws IOException { s1.write(b); s2.write(b); } public void write(byte[] b, int off, int len) throws IOException { s1.write(b, off, len); s2.write(b, off, len); } public void write(int b) throws IOException { s1.write(b); s2.write(b); } }
You can use it like this:
Now every call to System.out.println(...) should output to both the text file Log.txt as well as to the console (if the console output was the System.out previously).try { FileOutputStream fileOut = new FileOutputStream("Log.txt"); System.setOut(new PrintStream(new SplitOutputStream(System.out, fileOut))); } catch (FileNotFoundException e1) { e1.printStackTrace(); }
Edit: I also wrote this little handy class that can output to a custom JFrame:
Since its a regular output stream you can use it as System.out and you can use it in combination with my SplitOutputStream. You can even have your output to file, console and to the JFrame all at once if you split it twice.import java.awt.BorderLayout; import java.awt.Rectangle; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.IOException; import java.io.OutputStream; import javax.swing.JButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class OutputToFrame extends OutputStream { private final StringBuffer buffer; private OutputFrame frame; private Rectangle frameBounds; public OutputToFrame() { buffer = new StringBuffer(); } public void write(int b) throws IOException { char inAsChar = (char) b; buffer.append(inAsChar); if (inAsChar == '\n') { flushToFrame(); } } public void flush() throws IOException { super.flush(); flushToFrame(); } public void close() throws IOException { super.close(); if (frame != null) { frame.dispose(); } } private void flushToFrame() { if (frame == null) { makeFrame(); } frame.append(buffer.toString()); buffer.delete(0, buffer.length()); } private void makeFrame() { frame = new OutputFrame(); if (frameBounds != null) { frame.setBounds(frameBounds); } frame.setVisible(true); frame.addWindowListener(new WindowListener() { public void windowOpened(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } public void windowClosing(WindowEvent e) { } public void windowClosed(WindowEvent e) { frame = null; } public void windowActivated(WindowEvent e) { } }); frame.addComponentListener(new ComponentListener() { public void componentShown(ComponentEvent e) { } public void componentResized(ComponentEvent e) { frameBounds = frame.getBounds(); } public void componentMoved(ComponentEvent e) { } public void componentHidden(ComponentEvent e) { } }); } private static class OutputFrame extends JFrame { static final long serialVersionUID = 1L; final JTextArea textArea; public OutputFrame() { setTitle("Output"); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setBounds(100, 100, 450, 300); JPanel contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(new BorderLayout(0, 0)); JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.SOUTH); panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); final JFrame self = this; JButton btnClose = new JButton("Close"); btnClose.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { self.dispose(); } }); panel.add(btnClose); JScrollPane scrollPane = new JScrollPane(); contentPane.add(scrollPane, BorderLayout.CENTER); textArea = new JTextArea(); scrollPane.setViewportView(textArea); } public void append(String s) { textArea.append(s); } } }