【问题标题】:Redirect console output to string in Java将控制台输出重定向到Java中的字符串
【发布时间】:2012-02-01 06:15:52
【问题描述】:

我有一种方法,它的返回类型是void,它直接在控制台上打印。

但是我需要在字符串中输出该输出,以便我可以处理它。

由于我无法对返回类型为 void 的方法进行任何更改,因此我必须将该输出重定向到字符串。

如何在 Java 中重定向它?

【问题讨论】:

    标签: java string redirect console stdout


    【解决方案1】:

    如果您使用的是 Spring Framework,那么使用 OutputCaptureExtension 可以很简单地做到这一点:

     @ExtendWith(OutputCaptureExtension.class)
     class MyTest {
    
         @Test
         void test(CapturedOutput output) {
             System.out.println("ok");
             assertThat(output).contains("ok");
             System.err.println("error");
         }
    
         @AfterEach
         void after(CapturedOutput output) {
             assertThat(output.getOut()).contains("ok");
             assertThat(output.getErr()).contains("error");
         }
    
     }
    

    【讨论】:

      【解决方案2】:

      虽然这个问题已经很老了,并且已经有了很好的答案,但我想提供一个替代方案。我专门为这个用例创建了一个库。它被称为Console Captor,您可以使用以下 sn-p 添加它:

      <dependency>
          <groupId>io.github.hakky54</groupId>
          <artifactId>consolecaptor</artifactId>
          <version>1.0.0</version>
          <scope>test</scope>
      </dependency>
      

      示例类

      public class FooService {
      
          public void sayHello() {
              System.out.println("Keyboard not responding. Press any key to continue...");
              System.err.println("Congratulations, you are pregnant!");
          }
      
      }
      

      单元测试

      import static org.assertj.core.api.Assertions.assertThat;
      
      import nl.altindag.console.ConsoleCaptor;
      import org.junit.jupiter.api.Test;
      
      public class FooServiceTest {
      
          @Test
          public void captureStandardAndErrorOutput() {
              ConsoleCaptor consoleCaptor = new ConsoleCaptor();
      
              FooService fooService = new FooService();
              fooService.sayHello();
      
              assertThat(consoleCaptor.getStandardOutput()).contains("Keyboard not responding. Press any key to continue...");
              assertThat(consoleCaptor.getErrorOutput()).contains("Congratulations, you are pregnant!");
              
              consoleCaptor.close();
          }
      }
      

      【讨论】:

        【解决方案3】:

        如果函数打印到System.out,您可以通过使用System.setOut 方法将System.out 更改为您提供的PrintStream 来捕获该输出。如果您创建一个连接到ByteArrayOutputStreamPrintStream,那么您可以将输出捕获为String

        例子:

        // Create a stream to hold the output
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        // IMPORTANT: Save the old System.out!
        PrintStream old = System.out;
        // Tell Java to use your special stream
        System.setOut(ps);
        // Print some output: goes to your special stream
        System.out.println("Foofoofoo!");
        // Put things back
        System.out.flush();
        System.setOut(old);
        // Show what happened
        System.out.println("Here: " + baos.toString());
        

        这个程序只打印一行:

        Here: Foofoofoo!
        

        【讨论】:

        • 别忘了,完成后,调用 System.out.flush(),然后将 System.out 切换回正常的(或者更准确地说,是以前的)System.out .我看到@Ernest 已将其添加到他的代码中。
        • 另外,不要忘记这会产生线程问题,不仅针对此方法(您可以通过同步它来解决),还针对打印到标准输出的任何其他代码。 baos.toString() 很容易成为 "Foofohello worldofoo!"
        • @tuskiomi 该字符串来自 ByteArrayOutputStream.toString() -- 参见示例代码的最后一行。
        • @ErnestFriedman-Hill :- 我有一个 c 实用程序,它根据选项返回一些值。我使用 java 执行了这个实用程序,输出在控制台上,如何读取这个控制台回显输出。没有与输出关联的流。因为我使用重定向到 CON: ex:- util.exe -o CON: ( CON: for console output in DOS )
        • @Mistakamikaze 不。就在您停止使用其他信息流之前。
        【解决方案4】:

        这是一个名为 ConsoleOutputCapturer 的实用程序类。它允许输出到现有的控制台,但在幕后不断捕获输出文本。您可以使用 start/stop 方法控制要捕获的内容。换句话说,调用 start 开始捕获控制台输出,一旦完成捕获,您可以调用 stop 方法,该方法返回一个 String 值,用于保存 start-stop 调用之间的时间窗口的控制台输出。不过这个类不是线程安全的。

        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();
                    }
                }
            }
        }
        

        【讨论】:

        • 非常好的解决方案,虽然我建议添加一点点,但在将其设置为 null 以释放所有资源之前,在 stop() 方法中调用 baos 流上的 close() 方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-14
        • 1970-01-01
        • 2011-05-16
        • 1970-01-01
        相关资源
        最近更新 更多