1.问题来源
由于需求有了新变化,需要将控制台输出的信息抓取后保存到数据库表和一个文件中各一份,并且不能影响原先控制台打印信息的展示。因此基于《Java获取控制台输出信息(优化版)》对实现方法做了进一步优化,以实现以上需求。
这里只有一个示例,可同时满足以上两个需求,用来将控制台信息保存到数据库表和一个指定的文件中,并且不影响控制台信息的正常打印。代码如下:
2.代码实现
2.1 自定义打印流工具类
2.1.1 CompositeOutputStream类
import java.io.IOException;
import java.io.OutputStream;
/**
* CompositeOutputStream类是一个自定义的输出流类,它将数据同时写入多个输出流中。
*/
public class CompositeOutputStream extends OutputStream {
/**
* 存储多个输出流的数组
*/
private OutputStream[] outputStreams;
/**
* 构造函数,接收多个输出流作为参数
*
* @param outputStreams 多个输出流
*/
public CompositeOutputStream(OutputStream... outputStreams) {
this.outputStreams = outputStreams;
}
/**
* 将指定字节写入每个输出流中
*
* @param b 要写入的字节
* @throws IOException 如果发生 I/O 错误
*/
@Override
public void write(int b) throws IOException {
for (OutputStream outputStream : outputStreams) {
outputStream.write(b);
}
}
/**
* 将指定范围内的字节数组写入每个输出流中
*
* @param b 要写入的字节数组
* @param off 起始偏移量
* @param len 要写入的字节数
* @throws IOException 如果发生 I/O 错误
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (OutputStream outputStream : outputStreams) {
outputStream.write(b, off, len);
}
}
/**
* 刷新每个输出流
*
* @throws IOException 如果发生 I/O 错误
*/
@Override
public void flush() throws IOException {
for (OutputStream outputStream : outputStreams) {
outputStream.flush();
}
}
/**
* 关闭每个输出流
*
* @throws IOException 如果发生 I/O 错误
*/
@Override
public void close() throws IOException {
for (OutputStream outputStream : outputStreams) {
outputStream.close();
}
}
}
2.1.2 TeeOutputStreamExt类
import java.io.IOException;
import java.io.OutputStream;
/**
* TeeOutputStreamExt类是一个自定义的输出流类,可以将数据同时写入主输出流和辅助输出流。
*/
public class TeeOutputStreamExt extends OutputStream {
/**
* 主输出流
*/
private OutputStream primaryStream;
/**
* 辅助输出流
*/
private OutputStream secondaryStream;
/**
* 构造函数,创建一个TeeOutputStreamExt对象。
* @param primaryStream 主输出流
* @param secondaryStreams 辅助输出流数组
* @throws IllegalArgumentException 如果未提供辅助输出流则抛出异常
*/
public TeeOutputStreamExt(OutputStream primaryStream, OutputStream... secondaryStreams) {
this.primaryStream = primaryStream;
if (secondaryStreams.length == 0) {
throw new IllegalArgumentException("请至少提供一个输出流");
}
// 创建一个CompositeOutputStream对象来同时写入多个辅助输出流
this.secondaryStream = new CompositeOutputStream(secondaryStreams);
}
/**
* 将指定字节写入主输出流和辅助输出流。
* @param b 要写入的字节
* @throws IOException 如果发生I/O错误
*/
@Override
public void write(int b) throws IOException {
// 将数据写入主输出流
primaryStream.write(b);
// 将数据写入辅助输出流
secondaryStream.write(b);
}
/**
* 将指定字节数组的一部分写入主输出流和辅助输出流。
* @param b 要写入的字节数组
* @param off 数组中的起始偏移量
* @param len 要写入的字节数
* @throws IOException 如果发生I/O错误
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
// 将字节数组的一部分写入主输出流
primaryStream.write(b, off, len);
// 将字节数组的一部分写入辅助输出流
secondaryStream.write(b, off, len);
}
/**
* 刷新主输出流和辅助输出流。
* @throws IOException 如果发生I/O错误
*/
@Override
public void flush() throws IOException {
// 刷新主输出流
primaryStream.flush();
// 刷新辅助输出流
secondaryStream.flush();
}
/**
* 关闭辅助输出流,不关闭主输出流。
* @throws IOException 如果发生I/O错误
*/
@Override
public void close() throws IOException {
// 不关闭主输出流,由调用方负责关闭
// primaryStream.close();
// 关闭辅助输出流
secondaryStream.close();
}
}
2.2 实现
/**
* 获取控制台输出信息
*
* @author user
*
*/
public class ConsoleOutputCaptureDemo {
public static void main(String[] args) {
captureConsoleOutput();
System.out.println("正常输出...");
}
/**
* 控制台输出的同时输出信息到指定文件中,并获取控制台输出信息在最后统一处理
*/
public static void captureConsoleOutput() {
// 保存原来的标准输出流
PrintStream originalOut = new PrintStream(System.out);
String output = "";
try (
// 创建字节数组输出流,用于捕获控制台输出信息
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 创建文件输出流,将控制台输出信息写入文件
FileOutputStream fileOutputStream = new FileOutputStream("f:/output.txt");
// 创建一个合成输出流,同时将输出信息分别写入标准输出流、字节数组输出流和文件输出流
TeeOutputStreamExt teeOutputStream = new TeeOutputStreamExt(originalOut, baos, fileOutputStream);
// 创建一个新的PrintStream,将其设置为当前的标准输出流,使得控制台输出信息被重定向到合成输出流中
PrintStream printStream = new PrintStream(teeOutputStream)
) {
// 设置为新的输出方式开始生效
System.setOut(printStream);
for (int i = 1; i <= 5; i++) {
System.out.println(i + ": 这条消息会同时在控制台中显示,并在字节数组输出流中存在");
Thread.sleep(1000);
}
// 获取捕获到的控制台输出
output = baos.toString();
} catch (Exception e) {
e.getMessage();
}
// 恢复原始的标准输出流
System.setOut(originalOut);
System.out.println();
System.out.println("-------------获取抓取到的控制台信息---------------");
System.out.println(output);
}
}