首页 > 编程语言 >Java获取控制台输出信息(优化版)

Java获取控制台输出信息(优化版)

时间:2023-08-17 11:32:57浏览次数:37  
标签:输出 Java mainStream PrintStream import 控制台 public

1.问题来源

       项目中有个新需求,需要将某个方法从控制台输出的信息抓取后保存

起来保存到数据库表中或者一个文件中,并且不能影响原先控制台打印信息的展示。因此基于《Java获取控制台输出信息》对实现方法做了进一步优化,以实现以上需求。


      这里仍然是两个示例,一个用来将控制台信息保存到数据库表中,另外一个则保存到指定的文件中,并且不影响控制台信息的正常打印。代码如下:

2.打印并获取打印信息

控制台可正常打印信息,并且将打印信息抓取出来进行下一步处理

2.1 自定义打印流工具类

import java.io.OutputStream;
import java.io.PrintStream;

/**
 * 继承自 `PrintStream`,可以同时将输出内容发送到两个不同的输出流。
 */
public class TeePrintStream extends PrintStream {
	private PrintStream secondStream; // 第二个输出流

	/**
	 * 构造函数,用于创建 `TeePrintStream` 对象。
	 *
	 * @param mainStream   主要的输出流
	 * @param secondStream 第二个输出流
	 */
	public TeePrintStream(OutputStream mainStream, OutputStream secondStream) {
		super(mainStream); // 调用父类 PrintStream 的构造函数,传入主要的输出流
		this.secondStream = new PrintStream(secondStream); // 创建第二个输出流
	}

	/**
	 * 将字节数组输出到主要和第二个输出流。
	 *
	 * @param buf 输出的字节数组
	 * @param off 数组的起始偏移量
	 * @param len 要写入的字节数
	 */
	@Override
	public void write(byte[] buf, int off, int len) {
		super.write(buf, off, len); // 将字节数组输出到主要输出流
		secondStream.write(buf, off, len); // 将字节数组输出到第二个输出流
	}

	/**
	 * 刷新主要和第二个输出流。
	 */
	@Override
	public void flush() {
		super.flush(); // 刷新主要输出流
		secondStream.flush(); // 刷新第二个输出流
	}

	/**
	 * 关闭第二个输出流。
	 */
	@Override
	public void close() {
		// super.close(); // 务必不要关闭,否则后续正常的标准输出流都无法生效
		secondStream.close(); // 关闭第二个输出流
	}
}

2.2 实现

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;

import com.qfx.modules.test.bean.TeePrintStream;

/**
 * 获取控制台输出信息
 */
/**
 * @author user
 *
 */
public class ConsoleOutputCaptureDemo {
	public static void main(String[] args) {
		ConsoleOutput();
		ConsoleOutputToFile();
		System.out.println("正常输出...");
	}

	/**
	 * 控制台输出的同时,获取控制台输出信息放在最后统一处理
	 */
	public static void ConsoleOutput() {
		// 保存原来的标准输出流
		PrintStream originalOut = new PrintStream(System.out);
		String output = "";
		try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
				TeePrintStream teePrintStream = new TeePrintStream(System.out, baos)) {
			System.setOut(teePrintStream);

			for (int i = 1; i <= 5; i++) {
				System.out.println(i + ": 这条消息会同时在控制台中显示,并在字节数组输出流中存在");
			}
			// 获取捕获到的控制台输出
			output = baos.toString();
		} catch (Exception e) {
			e.getMessage();
		}
        
		// 恢复原始的标准输出流
		System.setOut(originalOut);
        
		System.out.println();
		System.out.println("-------------获取抓取到的控制台信息---------------");
		System.out.println(output);
	}
}

2.3 效果

可以看到正常打印的同时抓取到了控制台打印信息,并重新进行了打印,而且后面的正常输出也没有受到影响

Java获取控制台输出信息(优化版)_System

3.打印并保存至文件中

3.1 自定义输出流工具类

import java.io.IOException;
import java.io.OutputStream;

/**
 * 输出流的复制工具,它可以将数据同时写入两个不同的输出流中。
 */
public class TeeOutputStream extends OutputStream {
	private OutputStream mainStream; // 第一个输出流
	private OutputStream outputStream2; // 第二个输出流

	/**
	 * 构造函数,用于创建一个TeeOutputStream对象。
	 *
	 * @param mainStream 第一个输出流
	 * @param outputStream2 第二个输出流
	 */
	public TeeOutputStream(OutputStream mainStream, OutputStream outputStream2) {
		this.mainStream = mainStream;
		this.outputStream2 = outputStream2;
	}

	/**
	 * 将指定的字节写入输出流中。
	 *
	 * @param b 要写入的字节
	 * @throws IOException 如果发生输入/输出异常
	 */
	@Override
	public void write(int b) throws IOException {
		mainStream.write(b);
		outputStream2.write(b);
	}

	/**
	 * 刷新输出流,确保所有缓冲的数据被写入目标流中。
	 *
	 * @throws IOException 如果发生输入/输出异常
	 */
	@Override
	public void flush() throws IOException {
		mainStream.flush();
		outputStream2.flush();
	}

	/**
	 * 关闭输出流,释放任何系统资源。
	 *
	 * @throws IOException 如果发生输入/输出异常
	 */
	@Override
	public void close() throws IOException {
		// mainStream.close();  // 务必不要关闭,否则后续正常的标准输出流都无法生效
		outputStream2.close();
	}
}

3.2 实现

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

import com.qfx.modules.test.bean.TeeOutputStream;

/**
 * 获取控制台输出信息
 */
public class ConsoleOutputCaptureDemo {
	
	public static void main(String[] args) {
		System.out.println();
		ConsoleOutputToFile();
		System.out.println("正常输出...");
	}

	/**
	 * 控制台输出信息的同时输出信息到指定文件中
	 */
	public static void ConsoleOutputToFile() {
		// 保存原来的标准输出流
		PrintStream originalOut = new PrintStream(System.out);
		try (FileOutputStream fileOutputStream = new FileOutputStream("f:/output.txt");
				TeeOutputStream teeOutputStream = new TeeOutputStream(System.out, fileOutputStream);
				PrintStream printStream = new PrintStream(teeOutputStream, true, "UTF-8")) {
			// 将标准输出流重定向到打印流
			System.setOut(printStream);
			
			for (int i = 1; i <= 10; i++) {
				System.out.println(i + ": 这条消息会同时在控制台和文件中显示");
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 恢复原始的标准输出流
		System.setOut(originalOut);
	}
}

3.3 效果

3.3.1 效果1

控制台打印信息的同时将信息保存到了指定的文件中

Java获取控制台输出信息(优化版)_java_02

3.3.2 效果2

可以看到,执行完打印并保存至文件中的操作,恢复了标准的输出流,后续的可以正常打印信息

Java获取控制台输出信息(优化版)_输出流_03

标签:输出,Java,mainStream,PrintStream,import,控制台,public
From: https://blog.51cto.com/abcd/7120061

相关文章

  • java springboot excel 上传
    spring.http.multipart.location=/data/server/upload/spring.http.multipart.max-file-size=2048MBspring.http.multipart.max-request-size=2048MBimportjava.io.File;importjavax.servlet.MultipartConfigElement;importorg.springframework.beans.factory.ann......
  • Java学习笔记(十二)
    7.5 内部类7.5.1 内部类概述1、什么是内部类?顾名思义:一个类里面的类称为内部类。例如:classOuter{//相对的,它是外部类classInner{//内部类}}2、为什么要用内部类?实现高内聚低耦合的开发原则。好处:(1)内部类,可以被限定在外部类中使用(2)内部类和外部类可以......
  • Java中Date方法详解
    先进行专栏介绍本专栏是自己学Java的旅途,纯手敲的代码,自己跟着黑马课程学习的,并加入一些自己的理解,对代码和笔记进行适当修改。希望能对大家能有所帮助,同时也是请大家对我进行监督,对我写的代码进行建议,互相学习。Date方法Date类是用于表示日期和时间的类。它提供了一系列的方......
  • Java导出Excel带格式工具类
    Java导出Excel里面有具体内容,带有格式。可以创建工具类直接去使用/***通用模版下载*@paramoutputStream以流的形式输出到浏览器*@paramexcelName下载excel的文件名称*@paramWaring提示语言*@paramtitleS标题列*@paramcontentS......
  • Java导出Excel带格式工具类
    Java导出Excel里面有具体内容,带有格式。可以创建工具类直接去使用/***通用模版下载*@paramoutputStream以流的形式输出到浏览器*@paramexcelName下载excel的文件名称*@paramWaring提示语言*@paramtitleS标题列*@paramcontentS......
  • 《控制台篇》头文件h和源文件cpp的区别
    头文件和源文件区别参考链接:https://zhidao.baidu.com/question/940855602014421372.html头文件和源文件在本质上没有任何区别。只不过一般:后缀为.h的文件是头文件,内含函数声明、宏定义、结构体定义等内容。后缀为.c的文件是源文件,内含函数实现,变量定义等内容。而且是什么后......
  • 使用控制台打印显示点阵字体库HZK24、ASC24
    1.创建codeblocks工程。  加入字库文件:https://files.cnblogs.com/files/blogs/799931/font.7z?t=1692239003&download=true2.编辑代码:intmain(void){FILE*fphzk=NULL;FILE*fpASC24=NULL;inti,j,k,offset;intflag;unsignedcha......
  • Java应用堆外内存泄露问题排查
    问题是怎么发现的最近有个java应用在做压力测试压测环境配置:CentOS系统4核CPU8g内存jdk1.6.0_25,jvm配置-server-Xms2048m-Xmx2048m出现问题如下执行300并发,压测持续1个小时后内存使用率从20%上升到100%,tps从1100多降低到600多。排查问题的详细过程首先使用top命令查......
  • java高级工程师需要掌握的知识
          结语学习没有捷径,一步一个脚印! ......
  • JavaScript中的标识符和保留字
    标识符。简单地说,标识符就是一个名字。在JavaScript中,标识符用于为JavaScript代码中的常量、变量、属性、函数和类命名,还可用于为某些循环提供标签。JavaScript标识符必须以字母、下划线(_)或美元符号($)开头。后续字符可以是字母、数字、下划线或美元符号(数字不能作为第一个字符,以区......