如何检测Python中向sys.stdout打印是否失败?
检测sys.stdout打印失败的解决方法
问题核心在于sys.stdout的缓冲机制:当stdout被重定向到文件(如/dev/full)时,默认是块缓冲模式,print操作不会立即将数据写入底层设备,而是暂存在缓冲区中。此时OSError会在缓冲区刷新(程序退出时自动触发)时抛出,而此时已经脱离了try块的捕获范围,导致异常被当作未处理异常输出。
要解决这个问题,需要强制触发缓冲区刷新,让异常在try块内被捕获,具体有两种常用方式:
方式一:手动调用flush()
在print之后显式调用flush(),强制将缓冲区数据写入设备,此时若写入失败会立即抛出OSError,可被try块捕获。
修改后的代码:
#! /usr/bin/env python3.12 import sys try: if len(sys.argv) > 1: out = open(sys.argv[1], 'w', buffering=1) else: out = sys.stdout print("call...", file=sys.stderr) print("data", file=out) out.flush() # 强制刷新缓冲区,触发可能的写入异常 print("return...", file=sys.stderr) except OSError as e: print(f"error: {e}", file=sys.stderr) sys.exit(1) finally: # 仅对自行打开的文件执行关闭操作,sys.stdout无需手动关闭 if out is not sys.stdout: out.close()
运行测试:
$ ./ftest.py > /dev/full call... error: [Errno 28] No space left on device
方式二:使用无缓冲模式
如果不需要缓冲,可以将sys.stdout设置为无缓冲模式,或者在打开文件时指定buffering=0(注意:文本模式下buffering=0仅Python 3.7+支持,需配合newline='')。这种方式会牺牲部分性能,适合对实时性要求极高的场景。
示例代码片段:
# 将sys.stdout改为无缓冲模式 sys.stdout = open(sys.stdout.fileno(), 'w', buffering=0, encoding=sys.stdout.encoding, newline='')
补充说明
- 当stdout连接终端时,默认是行缓冲,print后的换行符会自动触发刷新,一般不会出现此问题;但重定向到文件/管道时会切换为块缓冲,必须手动处理。
- 不要直接关闭sys.stdout,这会导致后续无法向标准输出写入。
内容的提问来源于stack exchange,提问作者Shaun
相关产品推荐
相关产品推荐

