我想编写一个可以表现为真正文件描述符的类。它的.fileno()方法应返回一个文件描述符,它提供POSIX系统所需的所有服务。
这是我第一次涉足POSIX系统编程,所以我可能会误解事情。
潜在的动机是希望使用内存中的Python对象作为stdin
或stdout
kwarg到subprocess.Popen
构造函数,而不必依赖临时或内存映射文件。但是我对一些能够完成工作的聪明技巧不感兴趣 - 我真的希望有一个能够回答所有相关系统调用的Python实现。
答案 0 :(得分:2)
你做不到。在Python世界之外的操作系统内核中跟踪POSIX文件描述符;你无法在Python代码中模拟它们。
答案 1 :(得分:2)
如果您想要一个可以在传递给系统调用时用作文件的类,它需要一个fileno(),它是一个真正的OS文件描述符。在不触及硬盘的情况下执行此操作的一种方法是使用管道,因为它们具有文件描述符,然后系统调用可以写入这些文件描述符。
我确实编写了一个使用这种技术为another answer做了一些事情的类。它并没有真正做你想做的事情,但使用管道的技术对你来说应该是可行的:
import io
import logging
import os
import select
import subprocess
import time
import threading
LOG_FILENAME = 'output.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
class StreamLogger(io.IOBase):
def __init__(self, level):
self.level = level
self.pipe = os.pipe()
self.thread = threading.Thread(target=self._flusher)
self.thread.start()
def _flusher(self):
self._run = True
buf = b''
while self._run:
for fh in select.select([self.pipe[0]], [], [], 0)[0]:
buf += os.read(fh, 1024)
while b'\n' in buf:
data, buf = buf.split(b'\n', 1)
self.write(data.decode())
time.sleep(1)
self._run = None
def write(self, data):
return logging.log(self.level, data)
def fileno(self):
return self.pipe[1]
def close(self):
if self._run:
self._run = False
while self._run is not None:
time.sleep(1)
os.close(self.pipe[0])
os.close(self.pipe[1])
答案 2 :(得分:0)
这是我第一次涉足POSIX系统编程,所以我可能会误解事情。
是的。
POSIX文件描述符只是数字 - 它们不是对象,因此您无法覆盖它们的方法。例如,0,1和2都是[通常]有效的文件描述符。
“相关系统调用”内置于Linux内核中。 Linux内核本身维护一个列表,将文件描述符映射到某个内部内核对象(它有方法!),但是你不能从Python插入新的文件描述符。在内核空间中运行的代码与普通(“用户模式”)代码非常不同。
我可以建议您查看subprocess.PIPE,以及stdout / stdin / stderr属性或subprocess.Popen对象上的communic()方法吗?这将允许您启动子进程,读取它输出的数据,并完全控制发送给它的数据。 (我认为这是你真正想做的......)。如果你很好奇,那么当你玩这个时,你可以查看subprocess.py源代码,了解它是如何工作的。
有一个subprocess.PIPE here的例子。
或者,如果您确实想在Python中实现完整的文件系统,请查看FUSE,它是Python bindings。 FUSE包含一个在内核中运行的C模块,并处理某个目录的文件系统请求。它通过将它们传递给用户空间程序来处理它们,该程序可以用Python编写。您可以从单独的 Python程序中打开这些文件,以获取文件描述符。这有点复杂,可能不是初学者开始的最佳场所。