如何获取无可见名称tempfile的两个独立文件对象/描述符?
获取无可见名称临时文件的独立文件对象/描述符的解决方案
刚好碰到过类似的场景,给你两个简洁的解决方案,完美避开你提到的死锁和额外线程的问题:
方法一:复制文件描述符并重新包装
SpooledTemporaryFile的问题在于数据量较小时会存在内存缓冲区,没有真正的磁盘文件描述符,所以先换成tempfile.TemporaryFile(Unix下会自动unlink,Windows下是隐藏状态,符合你“无可见名称”的需求),然后通过os.dup复制文件描述符,再包装成新的文件对象。
需要注意:两个文件对象共享底层的文件偏移量,所以一定要等子进程写完并退出后,再将读指针移到文件开头读取。
示例代码:
import tempfile import os import subprocess # 创建无可见名称的临时文件 tmp_writer = tempfile.TemporaryFile() # 复制文件描述符,生成独立的读用描述符 dup_fd = os.dup(tmp_writer.fileno()) tmp_reader = os.fdopen(dup_fd, 'rb') # 启动子进程,输出写入临时文件 p = subprocess.Popen(['command'], stdin=subprocess.PIPE, stdout=tmp_writer) for d in get_data(): p.stdin.write(d) p.stdin.close() # 关闭输入,告知子进程数据发送完毕 p.wait() # 等待子进程处理完成 # 将读指针移到文件开头 tmp_reader.seek(0) # 读取子进程输出的结果 result = tmp_reader.read() # 清理资源 tmp_writer.close() tmp_reader.close()
方法二:用mkstemp手动创建无名称临时文件
tempfile.mkstemp会返回文件描述符和临时文件名,我们立即unlink文件名,就能得到无可见名称的临时文件,再基于这个描述符创建读写两个文件对象:
示例代码:
import tempfile import os import subprocess # 创建临时文件,获取描述符和文件名 fd, tmp_path = tempfile.mkstemp() # 立即删除文件名,让文件变成无可见名称的临时文件 os.unlink(tmp_path) # 基于原fd创建写文件对象 tmp_writer = os.fdopen(fd, 'wb') # 复制fd创建读文件对象 dup_fd = os.dup(fd) tmp_reader = os.fdopen(dup_fd, 'rb') # 执行子进程任务 p = subprocess.Popen(['command'], stdin=subprocess.PIPE, stdout=tmp_writer) for d in get_data(): p.stdin.write(d) p.stdin.close() p.wait() # 移动读指针到开头读取结果 tmp_reader.seek(0) result = tmp_reader.read() # 关闭文件对象 tmp_writer.close() tmp_reader.close()
关键提醒
- 不要用
SpooledTemporaryFile:它在数据未超过阈值时会存在内存中,没有真正的磁盘文件描述符,os.dup无法生效;如果一定要用,必须先调用rollover()强制将数据写入磁盘,但这样就失去了它的内存缓存优势。 - 必须等待子进程结束后再读取:否则会读到不完整的数据,甚至引发阻塞。
- 跨平台兼容:以上代码在Python 3.6+版本中,Unix和Windows系统都能正常工作。
内容的提问来源于stack exchange,提问作者Congbin Guo
相关产品推荐
相关产品推荐

