如何实现Python代码输出同时写入txt文件并在终端显示?
Python实现print同时输出到终端和文件的方法
问题原因
直接将sys.stdout赋值为文件对象会完全覆盖默认的终端输出流,所有print输出只会流向指定文件,无法在终端展示,直接关闭文件句柄还可能导致后续标准输出报错。
原始问题代码:
import sys from librk2.auth import Auth from librk2.exceptions import LibrkError from librk2.cr.server import CrServer from librk2.helpers.ip4finder import IP4Finder try: auth = Auth('my program', interactive=True) server = IP4Finder(auth, "1.1.1.1") deviceid = CrServer(auth, (server.device_id)) except LibrkError as ex: print(ex.message) sys.exit(ex.code) sys.stdout=open("test.txt","w") print("Current Machine type: {0}".format(deviceid.os_type)) sys.stdout.close()
可选实现方案
方案1:自定义双输出流类(无依赖,最小改动原有代码)
自定义类同时持有终端原始输出流和日志文件流,写入操作同步发送到两个流,改动量最小:
import sys from librk2.auth import Auth from librk2.exceptions import LibrkError from librk2.cr.server import CrServer from librk2.helpers.ip4finder import IP4Finder class DualStream: def __init__(self, *output_streams): self.streams = output_streams def write(self, content): for s in self.streams: s.write(content) s.flush() # 实时刷新缓存,避免输出延迟 def flush(self): for s in self.streams: s.flush() if __name__ == "__main__": try: auth = Auth('my program', interactive=True) server = IP4Finder(auth, "1.1.1.1") deviceid = CrServer(auth, (server.device_id)) except LibrkError as ex: print(ex.message) sys.exit(ex.code) # 保存原始终端输出流 origin_stdout = sys.stdout # 打开日志文件,指定utf-8编码避免乱码 log_file = open("test.txt", "w", encoding="utf-8") # 替换标准输出为双路流 sys.stdout = DualStream(origin_stdout, log_file) # 后续print会同时输出到终端和文件 print("Current Machine type: {0}".format(deviceid.os_type)) # 用完恢复原始输出流,关闭文件 sys.stdout = origin_stdout log_file.close()
注意事项:
- 打开文件时指定
encoding="utf-8",避免Windows等系统下中文输出乱码 - 每次写入后执行flush操作,避免缓存导致终端或文件内容不实时
- 程序退出前必须恢复原始stdout、关闭文件句柄,防止资源泄漏
方案2:使用标准库logging(适合长期维护的日志场景)
如果后续需要扩展日志级别、时间戳、日志切割等能力,直接使用Python内置的logging模块更稳定,不需要手动维护流对象:
import logging import sys from librk2.auth import Auth from librk2.exceptions import LibrkError from librk2.cr.server import CrServer from librk2.helpers.ip4finder import IP4Finder # 配置日志同时输出到终端和文件 logging.basicConfig( level=logging.INFO, format="%(message)s", # 如需加时间、日志级别可修改格式,比如"%(asctime)s - %(levelname)s - %(message)s" handlers=[ logging.FileHandler("test.txt", encoding="utf-8"), logging.StreamHandler(sys.stdout) ] ) logger = logging.getLogger() try: auth = Auth('my program', interactive=True) server = IP4Finder(auth, "1.1.1.1") deviceid = CrServer(auth, (server.device_id)) except LibrkError as ex: logger.error(ex.message) sys.exit(ex.code) logger.info("Current Machine type: {0}".format(deviceid.os_type))
该方案无需手动处理流的关闭、恢复逻辑,模块会自动管理资源,扩展性更强。
内容的提问来源于stack exchange,提问作者Navdeep.D2
相关产品推荐
相关产品推荐

