2010-12-02 14 views

Respuesta

17

Ok, este fue un problema divertido. No parece ser una forma elegante de resolverlo para todos los métodos PrintStream a la vez. (Desafortunadamente, no hay FilterPrintStream.)

he escrito hasta una solución basada en la reflexión fea aunque (no para ser utilizado en el código de producción supongo :)

class LoggedPrintStream extends PrintStream { 

    final StringBuilder buf; 
    final PrintStream underlying; 

    LoggedPrintStream(StringBuilder sb, OutputStream os, PrintStream ul) { 
     super(os); 
     this.buf = sb; 
     this.underlying = ul; 
    } 

    public static LoggedPrintStream create(PrintStream toLog) { 
     try { 
      final StringBuilder sb = new StringBuilder(); 
      Field f = FilterOutputStream.class.getDeclaredField("out"); 
      f.setAccessible(true); 
      OutputStream psout = (OutputStream) f.get(toLog); 
      return new LoggedPrintStream(sb, new FilterOutputStream(psout) { 
       public void write(int b) throws IOException { 
        super.write(b); 
        sb.append((char) b); 
       } 
      }, toLog); 
     } catch (NoSuchFieldException shouldNotHappen) { 
     } catch (IllegalArgumentException shouldNotHappen) { 
     } catch (IllegalAccessException shouldNotHappen) { 
     } 
     return null; 
    } 
} 

... que puede ser utilizado como esto:

public class Test { 
    public static void main(String[] args) { 

     // Create logged PrintStreams 
     LoggedPrintStream lpsOut = LoggedPrintStream.create(System.out); 
     LoggedPrintStream lpsErr = LoggedPrintStream.create(System.err); 

     // Set them to stdout/stderr 
     System.setOut(lpsOut); 
     System.setErr(lpsErr); 

     // Print some stuff 
     System.out.print("hello "); 
     System.out.println(5); 
     System.out.flush(); 

     System.err.println("Some error"); 
     System.err.flush(); 

     // Restore System.out/System.err 
     System.setOut(lpsOut.underlying); 
     System.setErr(lpsErr.underlying); 

     // Print the logged output 
     System.out.println("----- Log for System.out: -----\n" + lpsOut.buf); 
     System.out.println("----- Log for System.err: -----\n" + lpsErr.buf); 
    } 
} 

salida resultante:

hello 5 
Some error 
----- Log for System.out: ----- 
hello 5 

----- Log for System.err: ----- 
Some error 

(Nota tho ugh, que el campo out en FilterOutputStream está protegido y documentado, por lo que es parte de la API :-)

+1

¡Guau! Muchas gracias. Esto funciona para mi. – Jacob

+0

No puedo obtener las 3 líneas. Comenzando desde 'Campo f' a' f.get (toLog) '. ¿Alguien me puede explicar? –

5

No puede hacer eso una vez que el programa haya terminado de ejecutarse. Debe hacerlo antes de que el programa comience a escribir la salida.

Consulte this article para obtener detalles sobre cómo reemplazar stdout y stderr. Las llamadas principales son System.setOut() y System.setErr().

0

No practico después, crear dos objetos StringBuilder antes de la primera System.out.print() es llamado y simplemente anexar cada cadena que desea guardar en el formato apropiado StringBuilder.

1

Puede utilizar PipedInputStream y PipedOutputStream.

//create pairs of Piped input and output streasm for std out and std err 
final PipedInputStream outPipedInputStream = new PipedInputStream(); 
final PrintStream outPrintStream = new PrintStream(new PipedOutputStream(
    outPipedInputStream)); 
final BufferedReader outReader = new BufferedReader(
    new InputStreamReader(outPipedInputStream)); 
final PipedInputStream errPipedInputStream = new PipedInputStream(); 
final PrintStream errPrintStream = new PrintStream(new PipedOutputStream(
    errPipedInputStream)); 
final BufferedReader errReader = new BufferedReader(
    new InputStreamReader(errPipedInputStream)); 
final PrintStream originalOutStream = System.out; 
final PrintStream originalErrStream = System.err; 
final Thread writingThread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      System.setOut(outPrintStream); 
      System.setErr(errPrintStream); 
      // You could also set the System.in here using a 
      // PipedInputStream 
      DoSomething(); 
      // Even better would be to refactor DoSomething to accept 
      // PrintStream objects as parameters to replace all uses of 
      // System.out and System.err. DoSomething could also have 
      // an overload with DoSomething() calling: 
      DoSomething(outPrintStream, errPrintStream); 
     } finally { 
      // may also want to add a catch for exceptions but it is 
      // essential to restore the original System output and error 
      // streams since it can be very confusing to not be able to 
      // find System.out output on your console 
      System.setOut(originalOutStream); 
      System.setErr(originalErrStream); 
      //You must close the streams which will auto flush them 
      outPrintStream.close(); 
      errPrintStream.close(); 
     } 
    } // end run() 
}); // end writing thread 
//Start the code that will write into streams 
writingThread.start(); 
String line; 
final List<String> completeOutputStreamContent = new ArrayList<String>(); 
while ((line = outReader.readLine()) != null) { 
    completeOutputStreamContent.add(line); 
} // end reading output stream 
final List<String> completeErrorStreamContent = new ArrayList<String>(); 
while ((line = errReader.readLine()) != null) { 
    completeErrorStreamContent.add(line); 
} // end reading output stream 
0

Estas dos líneas de código colocarán su salida en un archivo de texto o usted puede cambiar el destino como lo requiera.

// Crear un archivo: System.setOut (nuevo PrintStream (nuevo FileOutputStream ("D: /MyOutputFile.txt"))); // Redirige la salida al archivo: System.out.println ("¡Hola a la secuencia de salida personalizada!");

esperan su ayuda u .. :)

0

Aquí es una clase de utilidad denominado ConsoleOutputCapturer. Permite que la salida vaya a la consola existente, pero detrás de la escena sigue capturando el texto de salida. Puede controlar qué capturar con los métodos de inicio/detención. En otras palabras, llame a start para comenzar a capturar la salida de la consola y una vez que termine de capturar puede llamar al método stop que devuelve un valor String que contiene la salida de la consola para la ventana de tiempo entre las llamadas start-stop. Sin embargo, esta clase no es segura para subprocesos.

import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.Arrays; import java.util.List; public class ConsoleOutputCapturer { private ByteArrayOutputStream baos; private PrintStream previous; private boolean capturing; public void start() { if (capturing) { return; } capturing = true; previous = System.out; baos = new ByteArrayOutputStream(); OutputStream outputStreamCombiner = new OutputStreamCombiner(Arrays.asList(previous, baos)); PrintStream custom = new PrintStream(outputStreamCombiner); System.setOut(custom); } public String stop() { if (!capturing) { return ""; } System.setOut(previous); String capturedValue = baos.toString(); baos = null; previous = null; capturing = false; return capturedValue; } private static class OutputStreamCombiner extends OutputStream { private List<OutputStream> outputStreams; public OutputStreamCombiner(List<OutputStream> outputStreams) { this.outputStreams = outputStreams; } public void write(int b) throws IOException { for (OutputStream os : outputStreams) { os.write(b); } } public void flush() throws IOException { for (OutputStream os : outputStreams) { os.flush(); } } public void close() throws IOException { for (OutputStream os : outputStreams) { os.close(); } } } }
Cuestiones relacionadas